Spring 为什么我的JdbcTokenStore会序列化Java对象?
所以我只是从MemoryTokenStore中的Spring 为什么我的JdbcTokenStore会序列化Java对象?,spring,spring-boot,spring-security,spring-oauth2,Spring,Spring Boot,Spring Security,Spring Oauth2,所以我只是从MemoryTokenStore中的移动到JdbcTokenStore。像往常一样,一个看似简单的改变之后,伴随着一些副作用,包括吞咽的例外——抱歉,这是一个咆哮 这是我用来访问用户主体的方式: Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String username = (String) authentication.getPrincipal();
移动到JdbcTokenStore
。像往常一样,一个看似简单的改变之后,伴随着一些副作用,包括吞咽的例外——抱歉,这是一个咆哮
这是我用来访问用户主体的方式:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = (String) authentication.getPrincipal();
弗斯特
出于某种原因,getPrincipal()
总是只返回用户名,而不是UserDetails
对象。这对我来说已经足够好了,所以我选择了它
现在我更改了令牌存储,getPrincipal()
确实返回了UserDetails
对象。我可以接受这一点,但我想知道为什么这一点突然发生了变化——我不得不重构一些代码,因为我一直希望用户名是从getPrincipal()
到现在为止。我也想知道我是否可以改变这一点
第二
据我所见,JdbcTokenStore
似乎序列化了Java对象。它尝试序列化标记
对象和用户详细信息
对象。列token
和authentication
似乎代表了那些序列化对象,我想理解为什么这实际上是必要的。毕竟,这些信息可以在启动/运行时从数据库中恢复。当然除了标记
,但我不明白为什么他们不存储标记(字符串
),而是存储对象
最重要的是:对这些类中的任何一个进行最轻微的更改,它们都不会被反序列化!如果其中一个类发生更改,每个用户都将被迫重新登录,这与我想首先使用JdbcTokenStore
的原因不符,因此一定有可疑之处,或者我没有得到它
也许有人能对此有更多的了解。看着你的咆哮,然后再看看你的代码,我也有点惊讶!它在幕后所做的实际上是将对象(如您所建议的!)序列化为一个看起来非常不友好的对象字符串:
protected byte[] serializeAccessToken(OAuth2AccessToken token) {
return SerializationUtils.serialize(token);
}
看起来我们应该做的(我不确定他们为什么没有在文档中指出这一点)是覆盖以下文件中的*serialize
方法:
这可能就是他们都受到保护的原因。实施可能如下所示:
class JacksonJdbcTokenStore extends JdbcTokenStore {
private ObjectMapper mapper;
public JdbcTokenStore(ObjectMapper mapper, DataSource dataSource) {
this.mapper = mapper;
super(dataSource);
}
protected byte[] serializeAuthentication(OAuth2Authentication authentication)
{
return mapper.writeValueAsBytes(authentication);
}
protected OAuth2Authentication deserializeAuthentication(byte[] authentication) {
return mapper.read(authentication, OAuth2Authentication.class);
}
// Same type of thing for the other serialize/deserialize operations...
}
我还没有实际尝试或测试上述代码,您可能需要修改序列化规则,但我只能告诉您这些
我可以对你这种奇怪的默认行为表示同情,但我不明白你为什么会在这里做错什么。我只能这么说了
仅供参考,对于第一个问题,我并不奇怪这些不同的实现可能会返回不同的
Principal
,这对于Authentication
实现来说是正常的,而Spring就是这样做的。Hmm。。覆盖默认实现不是我想做的事情,但这是一个好主意。然而,我认为这可能会使很多事情复杂化,因为当我反序列化(用户名)时,我必须从这个对象创建一个OAuth2Authentication
对象,我想,这将需要额外的代码。我不确定是否可以这样做,但我会尝试。啊,我也必须改变行为getPrincipal()
还必须只返回用户名..好的,我可能看到了这里的困难,也可能是OAuth2Authentication
为oauth\u access\u token
表的authentication
列序列化的原因。此对象还包含一个OAuth2Request
对象,该对象似乎包含有关用户身份验证的一些基本信息。我相信这是他们这么做的主要原因。我不得不说这很奇怪——主要是因为“如果我更改了UserDetails类会发生什么?”。因此,我认为要解决所有这些问题,我认为有可能..让getPrincipal()
只返回用户名。这样一来,OAuth2Authentication
不会保存例如MyUserDetailsImpl
,而只是一个字符串。现在,只有对OAuth2Authentication
类中的任何内容进行更改(我猜),事情才会破裂^^我不必担心他们的变化。如果他们是这样做的,他们很可能会考虑到向后兼容性。如果您担心他们不会这样做(可能!),您可以使用此序列化解决方案,将其与Spring版本一起进行版本设置,并在进行反序列化时将其作为提示
class JacksonJdbcTokenStore extends JdbcTokenStore {
private ObjectMapper mapper;
public JdbcTokenStore(ObjectMapper mapper, DataSource dataSource) {
this.mapper = mapper;
super(dataSource);
}
protected byte[] serializeAuthentication(OAuth2Authentication authentication)
{
return mapper.writeValueAsBytes(authentication);
}
protected OAuth2Authentication deserializeAuthentication(byte[] authentication) {
return mapper.read(authentication, OAuth2Authentication.class);
}
// Same type of thing for the other serialize/deserialize operations...
}