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

Spring Security自定义登录后重定向失效问题求助

问题排查与解决方案

核心原因分析

默认登录页正常但自定义JS登录后跳转失效,本质是会话关联失败——认证成功后,后续请求无法识别已登录的会话,大概率由以下几点导致:


1. CSRF令牌缺失(最常见)

Spring Security默认启用CSRF保护,默认登录页会自动注入CSRF令牌并在提交时携带,但自定义JS请求若未携带该令牌,会导致认证逻辑执行成功,但会话无法被正确绑定到当前用户,后续请求被判定为未认证。

解决方法:

  • 在登录页面的HTML头部添加CSRF令牌元标签:
    <meta name="_csrf" content="${_csrf.token}">
    <meta name="_csrf_header" content="${_csrf.headerName}">
    
  • 在JS的POST请求中携带令牌,同时确保携带会话Cookie:
    function login() {
      const csrfToken = document.querySelector('meta[name="_csrf"]').content;
      const csrfHeader = document.querySelector('meta[name="_csrf_header"]').content;
      const username = document.getElementById('username').value;
      const password = document.getElementById('password').value;
    
      fetch('/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          [csrfHeader]: csrfToken
        },
        body: new URLSearchParams({ username, password }),
        credentials: 'include' // 必须添加,确保会话Cookie被携带
      })
      .then(response => {
        if (response.ok) {
          window.location.href = '/valide'; // 手动跳转,避免XHR自动跟随重定向的Cookie丢失问题
        }
      });
    }
    

2. 请求格式不匹配

Spring Security默认的UsernamePasswordAuthenticationFilter只处理application/x-www-form-urlencoded格式的请求,若你的JS发送的是JSON格式(application/json),会导致认证逻辑无法解析凭证,看似重定向成功但实际未完成认证。

解决方法:

如果需要支持JSON登录,需在Security配置中添加自定义过滤器:

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login", "/js/**").permitAll()
                .requestMatchers("/valide").authenticated()
            )
            .formLogin(form -> form
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/valide")
                .permitAll()
            )
            // 添加JSON认证过滤器
            .addFilterBefore(jsonAuthFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public JsonAuthenticationFilter jsonAuthFilter() throws Exception {
        JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/valide"));
        return filter;
    }

    // 自定义JSON认证过滤器实现示例
    static class JsonAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
        protected JsonAuthenticationFilter() {
            super(new AntPathRequestMatcher("/login", "POST"));
        }

        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException {
            // 解析JSON格式的用户名密码
            LoginRequest loginRequest = new ObjectMapper().readValue(request.getInputStream(), LoginRequest.class);
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                loginRequest.getUsername(), loginRequest.getPassword()
            );
            return getAuthenticationManager().authenticate(authToken);
        }
    }

    // 辅助DTO类
    static class LoginRequest {
        private String username;
        private String password;
        // getter/setter
    }
}

3. 会话Cookie未被携带

若JS请求未配置携带Cookie,即使认证成功,后续跳转请求也无法携带会话ID,导致服务器无法识别已登录用户。

关键检查点:

  • 确认JS请求中设置了credentials: 'include'(同域请求)或credentials: 'same-origin'。
  • 检查浏览器Cookie设置,确保允许该站点的Cookie。
  • 查看Security配置未禁用Cookie会话跟踪:
    http.sessionManagement(session -> session
        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 默认配置,不要改为STATELESS
    );
    

4. 日志排查验证

查看Spring Security的DEBUG日志,重点关注以下内容:

  • 搜索UsernamePasswordAuthenticationFilter,确认是否输出Authentication success日志,以及认证后的用户信息。
  • 搜索SecurityContextPersistenceFilter,确认SecurityContext是否被正确保存到会话中(日志包含SecurityContext stored to HttpSession)。
  • 搜索CsrfFilter,若出现Invalid CSRF token found for,说明CSRF令牌未正确携带。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 00:35:35