Spring Boot 3中不能用RedisTokenStore,因其属已废弃的spring-security-oauth2,与Security 6+不兼容;应改用函数式配置,登录后双写JWT与LoginUser至Redis,并在JwtAuthenticationFilter中解析JWT查Redis恢复认证上下文。

Spring Boot 3 中不能直接用 RedisTokenStore(它属于已废弃的 spring-security-oauth2),也不能靠 WebSecurityConfigurerAdapter 配置——这个类在 Spring Security 6+(即 Boot 3 默认集成的版本)里彻底移除了。必须用函数式安全配置 + 自定义逻辑来把用户认证状态存进 Redis。
为什么不能直接用 RedisTokenStore
RedisTokenStore 是 spring-security-oauth2(2.x)时代的产物,依赖 AuthorizationServerConfigurerAdapter 和老版 OAuth2 流程。Spring Boot 3 默认使用 Spring Security 6.x + spring-authorization-server(官方新授权服务器),它不兼容该类。强行引入旧依赖会导致:
NoClassDefFoundError: org/springframework/security/oauth2/common/DefaultOAuth2AccessToken- 与
SecurityFilterChain冲突,启动失败 - JWT 解析、token 刷新等行为无法对齐新规范
正确做法:用 Redis 存 LoginUser + Token(JWT)双写
核心是放弃“自动 token 存储”,改为主动控制:登录成功后,生成 JWT,同时把 LoginUser 实体以 userId 或 token 为 key 存入 Redis,并设置过期时间(建议与 JWT 一致)。后续校验时,解析 JWT 得到 userId 或 username,再查 Redis 拿完整用户信息和权限。
关键点:
- 存的时候用
redisTemplate.opsForValue().set("login:user:1001", loginUser, Duration.ofHours(2)) - 读的时候用
redisTemplate.opsForValue().get("login:user:1001"),返回null表示 token 已失效或用户被踢下线 - 务必在
LoginUser类上加@JsonIgnore修饰掉getAuthorities()等可能引发反序列化异常的方法(尤其用 Jackson2RedisSerializer 时) - 不要把整个
Authentication对象塞进 Redis —— 它含大量不可序列化字段,会报NotSerializableException
过滤器中如何安全读取 Redis 用户信息
自定义一个 JwtAuthenticationFilter,继承 OncePerRequestFilter,在 doFilterInternal 里完成:解析 JWT → 提取 sub(通常是 userId)→ 查 Redis → 构造 UsernamePasswordAuthenticationToken 并塞进 SecurityContextHolder。
注意几个易错细节:
- 必须检查
redisTemplate.opsForValue().get(...)返回是否为null,否则 NPE - 若用
StringRedisTemplate,需自己手动JSON.parseObject(..., LoginUser.class),别指望自动反序列化 - 不要在过滤器里调用
authenticationManager.authenticate(...)—— 这是登录环节的事,此处只需“恢复上下文” - 确保该过滤器在
UsernamePasswordAuthenticationFilter之后、FilterSecurityInterceptor之前注册
CSRF 和 403 常见干扰项
Spring Boot 3 + Security 默认开启 CSRF 保护,但 JWT 场景下应禁用。不是简单加 http.csrf().disable() 就完事——你得确认它没被其他配置覆盖。常见坑:
- 如果用了
@EnableMethodSecurity却没配@Bean的SecurityFilterChain,CSRF 设置可能不生效 - 前端请求头没带
Authorization: Bearer xxx,或 token 格式错误(比如少了Bearer前缀),会被当成未认证请求,直接 403 - Redis 连接失败时,
redisTemplate抛出RedisConnectionFailureException,若没 try-catch,整个过滤器中断,请求也变 403 - 用户权限列表为空(
getAuthorities()返回空集合),会导致FilterSecurityInterceptor拒绝所有受保护资源
真正麻烦的从来不是“怎么存”,而是“什么时候删”——token 续期、主动登出、踢人下线,这些操作都得同步清理 Redis 里的对应 key,漏一条就可能让过期凭证继续生效。


















