OAuth2Authentication对象反序列化(RedisTokenStore)

发布于 2025-01-15 01:02:57 字数 2187 浏览 1 评论 0原文

我正在尝试重写一些使用 org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore 来存储访问令牌的旧代码。我目前正在尝试使用 RedisTokenStore 而不是以前使用的 InMemoryTokenStore。令牌生成并存储在 Redis 中(独立 redis 配置),但是,OAuth2Authentication 的反序列化失败并出现以下错误:

Could not read JSON: Cannot construct instance of `org.springframework.security.oauth2.provider.OAuth2Authentication` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

由于此类没有默认构造函数,因此反序列化并映射到实际的从 Redis 查找时对象失败。

RedisTokenStore redisTokenStore = new RedisTokenStore(jedisConnectionFactory);
redisTokenStore.setSerializationStrategy(new StandardStringSerializationStrategy() {
        @Override    
        protected <T> T deserializeInternal(byte[] bytes, Class<T> aClass) {
            return Utilities.parse(new String(bytes, StandardCharsets.UTF_8),aClass);
        }
                
        @Override    
        protected byte[] serializeInternal(Object o) {       
            return Objects.requireNonNull(Utilities.convert(o)).getBytes();
        }
});
this.tokenStore = redisTokenStore;



public static <T> T parse(String json, Class<T> clazz) {    
                try {        
                    return OBJECT_MAPPER.readValue(json, clazz);    
                } catch (IOException e) {        
                    log.error("Jackson2Json failed: " + e.getMessage());    
                }    return null;}
            
            public static String convert(Object data) {    
                try {        
                    return OBJECT_MAPPER.writeValueAsString(data);    
                } catch (JsonProcessingException e) {        
                    log.error("Conversion failed: " + e.getMessage());    
                }    
                return null;
            }

从 Redis 查找令牌时,OAuth2Authentication 对象如何重建?由于它没有定义默认构造函数,因此任何基于 Jackson 的序列化器和对象映射器将无法反序列化它。

同样,序列化效果很好(因为 OAuth2Authentication 实现了 Serialized 接口)并且令牌可以很好地存储在 Redis 中。当调用 /oauth/check_token 时它就会失败。

在 Redis 中存储访问令牌时我缺少什么以及如何处理这个问题?

I'm trying to rewrite some legacy code which used org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore to store the access tokens. I'm currently trying to use the RedisTokenStore instead of the previously used InMemoryTokenStore. The token gets generated and gets stored in Redis fine (Standalone redis configuration), however, deserialization of OAuth2Authentication fails with the following error:

Could not read JSON: Cannot construct instance of `org.springframework.security.oauth2.provider.OAuth2Authentication` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Since there's no default constructor for this class, the deserialization and mapping to the actual object while looking up from Redis fails.

RedisTokenStore redisTokenStore = new RedisTokenStore(jedisConnectionFactory);
redisTokenStore.setSerializationStrategy(new StandardStringSerializationStrategy() {
        @Override    
        protected <T> T deserializeInternal(byte[] bytes, Class<T> aClass) {
            return Utilities.parse(new String(bytes, StandardCharsets.UTF_8),aClass);
        }
                
        @Override    
        protected byte[] serializeInternal(Object o) {       
            return Objects.requireNonNull(Utilities.convert(o)).getBytes();
        }
});
this.tokenStore = redisTokenStore;



public static <T> T parse(String json, Class<T> clazz) {    
                try {        
                    return OBJECT_MAPPER.readValue(json, clazz);    
                } catch (IOException e) {        
                    log.error("Jackson2Json failed: " + e.getMessage());    
                }    return null;}
            
            public static String convert(Object data) {    
                try {        
                    return OBJECT_MAPPER.writeValueAsString(data);    
                } catch (JsonProcessingException e) {        
                    log.error("Conversion failed: " + e.getMessage());    
                }    
                return null;
            }

How is OAuth2Authentication object reconstructed when the token is looked up from Redis? Since it does not define a default constructor, any Jackson based serializer and object mapper won't be able to deserialize it.

Again, the serialization works great (since OAuth2Authentication implements Serializable interface) and the token gets stored fine in Redis. It just fails when the /oauth/check_token is called.

What am I missing and how is this problem dealt with while storing access token in Redis?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

落日海湾 2025-01-22 01:02:57

我通过编写自定义解串器解决了这个问题。它看起来像这样:

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.security.oauth2.core.AuthorizationGrantType;

import java.io.IOException;

public class AuthorizationGrantTypeCustomDeserializer extends JsonDeserializer<AuthorizationGrantType> {

    @Override
    public AuthorizationGrantType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
        Root root = p.readValueAs(Root.class);
        return root != null ?  new AuthorizationGrantType(root.value) : new AuthorizationGrantType("");
    }

    private static class Root {
        public String value;
    }

    public static SimpleModule generateModule() {
        SimpleModule authGrantModule = new SimpleModule();
        authGrantModule.addDeserializer(AuthorizationGrantType.class, new AuthorizationGrantTypeCustomDeserializer());
        return authGrantModule;
    }
}

然后我在 objectMapper 中注册了反序列化器,稍后由 jackson API 使用

 ObjectMapper mapper = new ObjectMapper()
                .registerModule(AuthorizationGrantTypeCustomDeserializer.generateModule());

I solved the issue by writing custom deserializer. It looks like this:

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.security.oauth2.core.AuthorizationGrantType;

import java.io.IOException;

public class AuthorizationGrantTypeCustomDeserializer extends JsonDeserializer<AuthorizationGrantType> {

    @Override
    public AuthorizationGrantType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
        Root root = p.readValueAs(Root.class);
        return root != null ?  new AuthorizationGrantType(root.value) : new AuthorizationGrantType("");
    }

    private static class Root {
        public String value;
    }

    public static SimpleModule generateModule() {
        SimpleModule authGrantModule = new SimpleModule();
        authGrantModule.addDeserializer(AuthorizationGrantType.class, new AuthorizationGrantTypeCustomDeserializer());
        return authGrantModule;
    }
}

Then I registered deserializer in objectMapper which is later used by jackson API

 ObjectMapper mapper = new ObjectMapper()
                .registerModule(AuthorizationGrantTypeCustomDeserializer.generateModule());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文