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

Spring Boot Security Redis共享会话登录失败问题求助

解决Spring Boot Security + Redis共享会话登录失败问题

我之前也碰到过几乎一模一样的Redis共享会话序列化问题,核心原因就是SessionRepositoryFilter$SessionRepositoryRequestWrapper$HttpSessionWrapper这个内部类没有实现Serializable接口,而默认的JDK序列化器无法处理它。给你几个经过验证的解决方案:

方案一:使用Jackson序列化器处理Security上下文

Spring Security提供了专门的Jackson模块来支持自身类的序列化,搭配Jackson2JsonRedisSerializer可以完美解决大部分序列化问题,步骤如下:

  1. 配置自定义的Redis序列化器,引入Security的Jackson模块:
@Configuration
public class RedisSessionConfig {

    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        
        // 注册Spring Security的Jackson模块,处理Security相关类的序列化
        objectMapper.registerModule(new SecurityJackson2Modules());
        
        // 配置Jackson支持所有属性访问,启用默认类型以处理多态
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        
        serializer.setObjectMapper(objectMapper);
        return serializer;
    }
}
  1. 确保你的Spring Boot依赖使用starter管理版本,避免版本冲突:
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

方案二:自定义SecurityContextRepository过滤不可序列化对象

如果不想修改Redis序列化器,也可以通过自定义HttpSessionSecurityContextRepository,在存储Security上下文时移除不可序列化的引用:

@Component
public class SerializableSecurityContextRepository extends HttpSessionSecurityContextRepository {

    @Override
    protected void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
        // 创建一个仅包含可序列化内容的SecurityContext副本
        SecurityContext serializableContext = new SecurityContextImpl();
        serializableContext.setAuthentication(context.getAuthentication());
        
        // 只存储纯净的SecurityContext,避免携带HttpSessionWrapper等不可序列化对象
        super.saveContext(serializableContext, request, response);
    }
}

然后在Security配置中指定使用这个自定义Repository:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private SerializableSecurityContextRepository securityContextRepository;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .securityContext(config -> config
                .securityContextRepository(securityContextRepository)
            )
            .formLogin(form -> form.permitAll())
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
            
        return http.build();
    }
}

方案三:检查版本兼容性

确保Spring Boot、Spring Security和Spring Session的版本完全兼容,建议直接使用Spring Boot的starter依赖,它会自动管理所有相关组件的版本,避免因版本不匹配导致的序列化异常。

补充排查点

  • 查看完整错误日志,确认是否抛出NotSerializableException,如果是,那基本就是这个内部类无法序列化的问题;
  • 检查Redis中存储的SPRING_SECURITY_CONTEXT键值,确认是否包含HttpSessionWrapper的引用;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:14:10