Spring Security登录成功但请求仍返回403问题(Spring Boot3)
核心原因
Spring Security 6.x(对应Spring Boot3.x)对SecurityContext的持久化机制做了更严格的约束,手动设置SecurityContextHolder后如果未通过官方的SecurityContextRepository完成持久化,后续请求无法加载已认证的上下文,最终被判定为匿名用户返回403。
具体排查与修复步骤
1. 完善登录逻辑的上下文持久化代码
你当前可能仅执行了类似以下的代码:
Authentication auth = authenticationManager.authenticate(authToken); SecurityContextHolder.getContext().setAuthentication(auth);
在Spring Security6中,这仅将上下文绑定到当前线程,不会自动持久化到请求会话或存储介质。后续请求的线程无法获取该上下文,因此被识别为匿名用户。
需要修改登录逻辑,注入SecurityContextRepository并显式保存上下文:
@Autowired private SecurityContextRepository securityContextRepository; // 登录成功后执行 Authentication authentication = authenticationManager.authenticate(authenticationToken); SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); securityContext.setAuthentication(authentication); SecurityContextHolder.setContext(securityContext); // 关键:将上下文持久化到当前请求的会话/存储介质 securityContextRepository.saveContext(securityContext, request, response);
2. 匹配场景配置SecurityContextRepository
- 有状态应用(依赖HttpSession):Spring Security默认使用
HttpSessionSecurityContextRepository,无需额外配置,确保上述saveContext调用即可完成会话持久化。 - 无状态应用(如JWT认证):需自定义
SecurityContextRepository,实现从请求头/参数中提取认证信息(如JWT令牌),并将解析后的Authentication加载到SecurityContext。示例框架:
public class JwtSecurityContextRepository implements SecurityContextRepository { @Override public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) { HttpServletRequest request = requestResponseHolder.getRequest(); String token = extractTokenFromRequestHeader(request); SecurityContext context = SecurityContextHolder.createEmptyContext(); if (token != null && validateTokenSignature(token)) { Authentication auth = parseTokenToAuthentication(token); context.setAuthentication(auth); } return context; } @Override public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) { // 无状态场景无需持久化,若需刷新令牌可在此扩展逻辑 } // 自行实现token提取、签名验证、解析为Authentication的逻辑 }
然后在SecurityConfig中配置生效:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .securityContext(context -> context .securityContextRepository(new JwtSecurityContextRepository()) ) // 其他权限规则、认证配置... }
3. 检查Session管理策略
若你配置了sessionCreationPolicy(SessionCreationPolicy.STATELESS),则默认的HttpSessionSecurityContextRepository会失效,必须搭配自定义的无状态SecurityContextRepository,否则后续请求无法加载认证上下文。
4. 验证Filter执行顺序
确保自定义的登录逻辑(如Controller或自定义Filter)在SecurityContextPersistenceFilter之后执行。该Filter负责在请求开始时从SecurityContextRepository加载上下文到SecurityContextHolder,若你的登录逻辑在它之前执行,保存的上下文会被后续流程覆盖。
额外验证手段
- 开启Spring Security调试日志(
logging.level.org.springframework.security=DEBUG),查看SecurityContextPersistenceFilter的日志输出,确认请求流程中是否成功加载到已认证的Authentication对象。 - 检查是否存在Session Fixation保护导致SessionID变更,若登录后SessionID发生变化,使用上述
securityContextRepository.saveContext方法可自动将上下文同步到新Session中。
内容的提问来源于stack exchange,提问作者Desidiam

