为什么我的JdbcTokenStore存储序列化的Java对象?

时间:2018-09-07 15:33:05

标签: spring spring-boot spring-security spring-oauth2

所以我只是从InMemoryTokenStore转到JdbcTokenStore。像往常一样,一个看似简单的变化之后会出现一些副作用,其中包括吞咽的异常现象-十分抱歉。

这是我过去访问用户主体的方式:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = (String) authentication.getPrincipal();

第一

由于某种原因,getPrincipal()始终仅返回用户名而不是UserDetails对象。这对我来说足够好了,所以我同意了。

现在我更改了令牌存储,getPrincipal() 确实确实返回了UserDetails对象。我可以接受,但是我想知道为什么这突然改变了-因为我一直期望用户名从getPrincipal()到现在,所以我不得不重构一些代码。我也想知道我是否可以更改它。

第二

据我所见,JdbcTokenStore似乎序列化了Java对象。它尝试序列化Token对象和UserDetails对象。 tokenauthentication列似乎代表了这些序列化的对象,我想理解为什么这实际上是必需的。毕竟,这是可以在启动/运行期间从数据库中恢复的信息。当然除了Token之外,但我不明白为什么他们不只是存储 token String)而是存储对象。

最重要的:对这些类中的任何一个都进行最小的更改,并且它们不会反序列化!如果更改了其中一个类,则每个用户都将被迫重新登录,这完全违背了我首先要使用JdbcTokenStore的原因-因此必定有一些可疑之处或我没有得到它

enter image description here


也许有人可以对此有所了解。

1 个答案:

答案 0 :(得分:0)

看着你的咆哮,然后看你的代码,我也有些惊讶!它实际上是在将对象序列化(如您建议的那样),变成看起来非常不友好的对象字符串:

protected byte[] serializeAccessToken(OAuth2AccessToken token) {
    return SerializationUtils.serialize(token);
}

似乎应该做什么(并且我不确定为什么他们没有在文档中指出这一点)是覆盖JdbcTokenStore中的*serialize方法:

protected OAuth2AccessToken deserializeAccessToken(byte[] token) 
protected OAuth2Authentication  deserializeAuthentication(byte[] authentication) 
protected OAuth2RefreshToken    deserializeRefreshToken(byte[] token) 
protected byte[] serializeAccessToken(OAuth2AccessToken token) 
protected byte[] serializeAuthentication(OAuth2Authentication authentication) 
protected byte[] serializeRefreshToken(OAuth2RefreshToken token)

这可能是为什么它们都受到保护的原因。该实现可能如下所示:

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所做的方式。