首页 > 解决方案 > 为什么我的 JdbcTokenStore 存储序列化 Java 对象?

问题描述

所以我只是从 移动InMemoryTokenStoreJdbcTokenStore。像往常一样,一个看似简单的更改之后会出现一些副作用,包括吞下异常 - 很抱歉咆哮。

这就是我用来访问用户主体的方式:

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

第一的

出于某种原因,getPrincipal()总是只返回用户名而不是UserDetails对象。这对我来说已经足够好了,所以我就去了。

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

第二

从我所见,JdbcTokenStore似乎序列化 Java 对象。它试图序列化一个Token对象和一个UserDetails对象。这些列似乎代表了那些序列tokenauthentication的对象,我想了解为什么这实际上是必要的。毕竟这是可以在启动/运行时从数据库中恢复的信息。当然除了Token,但我不明白为什么他们不只存储令牌(the String)而是存储对象。

最重要的是:对这些类中的任何一个进行最轻微的更改,它们都不会被反序列化!如果其中一个类被更改,那么每个用户都将被迫重新登录,这违背了我JdbcTokenStore首先要使用的原因 - 所以一定有一些可疑的东西,否则我没有得到它。

在此处输入图像描述


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

标签: springspring-bootspring-securityspring-oauth2

解决方案


看着你的咆哮,然后看着你的代码,我也有点惊讶!它在幕后所做的实际上是将对象(就像你建议的那样!)序列化为一个看起来非常不友好的对象字符串:

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

看起来应该做什么(我不确定他们为什么不在文档中指出这一点)是覆盖以下*serialize方法JdbcTokenStore

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的 's 并不感到惊讶,这对于实现来说是正常的,而Authentication这正是 Spring 的做法。


推荐阅读