You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Redis自定义OidcUser跨应用会话共享配置咨询

解决方案

方案1:主应用存储会话时转换为标准OidcUser

核心思路是不在Redis中存储自定义的CustomOidcUser实例,而是在认证成功后将其转换为Spring Security提供的标准OidcUser再存入会话:

  • 自定义认证成功处理器,替换Authentication中的用户对象:
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        if (authentication.getPrincipal() instanceof CustomOidcUser customUser) {
            // 基于自定义用户的信息构建标准OidcUser
            OidcUser standardOidcUser = new DefaultOidcUser(
                customUser.getAuthorities(),
                customUser.getIdToken(),
                customUser.getUserInfo()
            );
            // 生成新的认证对象并更新上下文
            Authentication newAuth = new OAuth2AuthenticationToken(
                standardOidcUser,
                standardOidcUser.getAuthorities(),
                authentication.getAuthorizedClientRegistrationId()
            );
            SecurityContextHolder.getContext().setAuthentication(newAuth);
        }
        super.onAuthenticationSuccess(request, response, authentication);
    }
}
  • 在Spring Security配置中启用该处理器:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .oauth2Login(oauth2 -> oauth2
                .successHandler(customAuthenticationSuccessHandler())
            );
        return http.build();
    }

    @Bean
    public CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler() {
        return new CustomAuthenticationSuccessHandler();
    }
}

方案2:共享CustomOidcUser类并统一Redis序列化

如果需要保留自定义用户的额外属性,可将CustomOidcUser抽为公共依赖Jar包,让所有共享会话的应用引入,同时统一Redis序列化配置确保反序列化兼容:

  • 所有应用配置统一的Redis会话序列化器,启用类型信息以识别自定义类:
@Configuration
public class RedisSessionConfig {
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        // 启用类型信息,让反序列化时能识别自定义类
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        serializer.setObjectMapper(mapper);
        return serializer;
    }
}

方案3:自定义UserDetails序列化/反序列化逻辑

通过自定义序列化规则,在主应用中将CustomOidcUser序列化为标准OidcUser的JSON结构,其他应用直接反序列化为标准OidcUser:

  • 主应用自定义序列化器,只序列化标准OidcUser所需字段:
public class OidcUserSerializer extends JsonSerializer<CustomOidcUser> {
    @Override
    public void serialize(CustomOidcUser value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeObjectField("authorities", value.getAuthorities());
        gen.writeObjectField("idToken", value.getIdToken());
        gen.writeObjectField("userInfo", value.getUserInfo());
        gen.writeEndObject();
    }
}
  • 其他应用自定义反序列化器,将JSON结构转为标准OidcUser:
public class OidcUserDeserializer extends JsonDeserializer<OidcUser> {
    @Override
    public OidcUser deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);
        Collection<? extends GrantedAuthority> authorities = ctxt.readValue(node.get("authorities"), new TypeReference<>() {});
        OidcIdToken idToken = ctxt.readValue(node.get("idToken"), OidcIdToken.class);
        OidcUserInfo userInfo = ctxt.readValue(node.get("userInfo"), OidcUserInfo.class);
        return new DefaultOidcUser(authorities, idToken, userInfo);
    }
}
  • 在各自应用的ObjectMapper中注册对应序列化/反序列化器(通过Mixin方式实现):
// 主应用配置
mapper.addMixIn(CustomOidcUser.class, OidcUserSerializerMixin.class);
abstract class OidcUserSerializerMixin {
    @JsonSerialize(using = OidcUserSerializer.class)
    abstract CustomOidcUser getPrincipal();
}

// 其他应用配置
mapper.addMixIn(OidcUser.class, OidcUserDeserializerMixin.class);
abstract class OidcUserDeserializerMixin {
    @JsonDeserialize(using = OidcUserDeserializer.class)
    abstract OidcUser getPrincipal();
}

内容的提问来源于stack exchange,提问作者yaroslav96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 09:25:19