Spring Security认证对象跨控制器/请求不持久问题咨询
Spring Security跨请求Authentication丢失问题解决方案
核心原因
你遇到的认证信息跨请求丢失,本质是Spring Security的上下文持久化机制没有正确执行,常见触发点包括手动操作Session时Key不匹配、过滤链未正确加载上下文、跨域场景下Session未正常传递三类。
修复步骤
- 移除手动操作HttpSession存SecurityContext的逻辑,改用Spring Security官方提供的持久化组件操作,避免常量值不匹配问题。登录逻辑中认证完成后按如下方式处理:
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(username, "password", privileges); Authentication auth = authenticationManager.authenticate(authToken); SecurityContext sc = SecurityContextHolder.getContext(); sc.setAuthentication(auth); // 用官方默认的Session持久化仓库存储上下文,无需手动拼常量操作Session new HttpSessionSecurityContextRepository().saveContext(sc, request, response);
- 补全安全配置中的Session管理规则,明确指定Session创建策略,避免框架默认配置被覆盖:
@Order(1) @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) @Conditional(OpenSecurityCondition.class) public class OpenSecurityConfig extends WebSecurityConfigurerAdapter { private final PasswordEncoder passwordEncoder; public OpenSecurityConfig(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } @Bean("authenticationManager") @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() // 明确指定Session策略:需要时创建会话,用于存储认证上下文 .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .and() .authorizeRequests() .anyRequest() .permitAll(); } }
- 排查跨域请求的Cookie传递配置:如果前后端不同源,前端请求需要开启携带凭证配置(例如axios设置
withCredentials: true),后端CORS配置需要开启allowCredentials(true),否则浏览器不会存储服务端返回的JSESSIONID,每次请求都会生成全新的匿名会话,自然读不到之前的认证信息。 - 不要手动构造带null凭证的未经过AuthenticationManager校验的Token直接塞入上下文:三个参数的UsernamePasswordAuthenticationToken构造器虽然会直接标记为已认证,但未走官方认证流程的Token可能会被安全过滤器判定为不可信,在请求处理过程中被重置为匿名用户。
为什么持久化逻辑没有默认生效
SecurityContext默认不会自动跨请求传递,这是Spring Security的设计逻辑,不是bug:
- SecurityContextHolder默认采用ThreadLocal策略存储认证信息,存储内容和当前请求线程绑定,请求结束后线程会被Tomcat等容器回收复用,ThreadLocal中的内容会被清空,不会自动保留到下一个请求。
- 跨请求的上下文持久化完全依赖
SecurityContextPersistenceFilter这个请求过滤器:它会在请求进入过滤链时,从配置的持久化仓库(默认是HttpSession)读取之前存储的SecurityContext绑定到当前线程的ThreadLocal;请求处理完成后,再把当前线程的SecurityContext存回持久化仓库,同时清空ThreadLocal避免线程复用导致的信息泄露。 - 这个过滤器只有在请求匹配到Spring Security过滤链时才会执行:如果你的配置类条件注解
@Conditional(OpenSecurityCondition.class)在部分请求场景下不生效、或者你手动把Session策略设为了STATELESS(无状态模式,常用于JWT鉴权场景)、或者你手动存Session时用的Key和框架默认读取的Key(SPRING_SECURITY_CONTEXT)不一致,过滤器就读取不到之前存的认证信息,会自动创建空上下文填充anonymousUser匿名身份。
内容的提问来源于stack exchange,提问作者eswaters
相关产品推荐
相关产品推荐

