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

Spring Security迁移FilterChain后登录重定向丢失AuthenticationToken问题

问题原因分析

你的配置存在两个核心冲突点,导致认证成功后会话无法正确保留AuthenticationToken:

  1. 登录过滤器重复配置:同时启用了formLogin()和自定义的MyAuthenticationFilter,两者都会处理登录请求。formLogin()会自动添加默认的UsernamePasswordAuthenticationFilter,和你自定义的过滤器处于同一执行位置,导致会话存储逻辑混乱。
  2. AuthenticationManager未注册为Bean:自定义的formUserAuthManager()没有标注@Bean注解,Spring Security无法将其纳入全局上下文管理,后续请求无法从会话中正确加载认证信息。
修复方案

步骤1:移除冲突的formLogin配置

既然已经自定义了登录过滤器,无需保留默认的formLogin()配置,避免过滤器重复执行:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.csrf(AbstractHttpConfigurer::disable)
        .requestCache(c -> c.requestCache(new CustomRequestCache()))
        .addFilterAt(getFormAuthFilter(), UsernamePasswordAuthenticationFilter.class)
        .authorizeHttpRequests(a -> a.requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
                                     .anyRequest().authenticated()
        )
        // 移除默认formLogin配置
        .headers(h -> h.frameOptions(FrameOptionsConfig::sameOrigin));

    return http.build();
}

步骤2:将AuthenticationManager注册为Bean

给formUserAuthManager()添加@Bean注解,让Spring容器管理该实例:

@Bean
AuthenticationManager formUserAuthManager() {
    return authentication -> authProvider().authenticate(authentication);
}

步骤3:确保自定义过滤器正确处理会话存储

如果MyAuthenticationFilter继承自AbstractAuthenticationProcessingFilter,需配置会话认证策略,确保认证信息存入会话:

public MyAuthenticationFilter() {
    super(new AntPathRequestMatcher("/login", "POST"));
    // 添加默认会话固定保护策略,自动处理会话存储
    setSessionAuthenticationStrategy(new SessionFixationProtectionStrategy());
}

同时检查MyLoginSuccessHandler,确保它没有破坏默认的会话保存逻辑,必要时手动绑定认证信息到会话:

public class MyLoginSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        // 将认证信息存入SecurityContext
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 绑定到HttpSession
        request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
        // 执行重定向逻辑
        response.sendRedirect("/dashboard");
    }
}

步骤4:检查CustomRequestCache实现

确保自定义请求缓存正确操作会话,避免干扰认证信息存储:

public class CustomRequestCache extends HttpSessionRequestCache {
    @Override
    public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
        // 仅保存非框架内部请求
        if (!SecurityUtils.isFrameworkInternalRequest(request)) {
            super.saveRequest(request, response);
        }
    }
}
验证要点
  • 登录成功后,检查HttpSession中是否存在SPRING_SECURITY_CONTEXT属性,且包含有效的Authentication对象。
  • 重定向后的请求,检查SecurityContextHolder.getContext().getAuthentication()是否不为空且不是匿名认证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 04:45:15