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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:27:23