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

Spring Security JWT中/login路径CSRF Token失效问题求助

Spring Security JWT场景下/login路径CSRF Token失效问题排查与解决

在JWT+Spring Security的无状态应用中启用CSRF后,发现/public/**等无需认证的路径可正常使用CSRF Token,但/login路径的CSRF校验始终不通过。以下是当前配置代码:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            //.csrf().disable()
            .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
            .addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig), JwtUsernameAndPasswordAuthenticationFilter.class)
            .authorizeRequests()
            .antMatchers("/", "index", "/css/*", "/js/*").permitAll()
            .antMatchers("/public/**").permitAll()
            .antMatchers("/api/**").hasRole(USER.name())
            .anyRequest()
            .authenticated();
}

核心原因

  1. 自定义登录过滤器未处理CSRF校验:Spring Security默认的UsernamePasswordAuthenticationFilter会自动集成CSRF校验逻辑,但你自定义的JwtUsernameAndPasswordAuthenticationFilter继承自AbstractAuthenticationProcessingFilter,默认不包含CSRF校验逻辑,导致登录请求绕过了CSRF校验环节(或校验失败后未正确抛出异常)。
  2. 过滤器执行顺序可能异常:如果自定义登录过滤器在CsrfFilter之前执行,会导致CSRF校验还未进行,登录请求就已被处理,最终表现为“CSRF Token失效”。

通俗易懂的解决步骤

步骤1:给自定义登录过滤器添加CSRF校验逻辑

在JwtUsernameAndPasswordAuthenticationFilter的attemptAuthentication方法开头,加入CSRF Token校验代码:

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    // 新增CSRF校验逻辑
    CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    if (csrfToken == null) {
        throw new MissingCsrfTokenException("未获取到CSRF Token");
    }
    // 从请求头获取前端传来的CSRF Token
    String requestCsrfToken = request.getHeader(csrfToken.getHeaderName());
    if (!csrfToken.getToken().equals(requestCsrfToken)) {
        throw new InvalidCsrfTokenException(csrfToken, requestCsrfToken);
    }

    // 原有登录逻辑...
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
    return getAuthenticationManager().authenticate(authRequest);
}

步骤2:确保CSRF过滤器优先执行

将自定义登录过滤器的添加方式改为addFilterBefore,确保CsrfFilter在登录过滤器之前运行:

// 替换原有的addFilter语句
http.addFilterBefore(
    new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey),
    UsernamePasswordAuthenticationFilter.class
);

步骤3:确认前端请求方式正确

因为使用CookieCsrfTokenRepository.withHttpOnlyFalse(),前端需要:

  • 从Cookie中读取XSRF-TOKEN值
  • 在/login请求的请求头中携带X-XSRF-TOKEN,值为读取到的Token

如果前端未按此方式传递Token,也会导致校验失败。

额外提醒

无状态应用并非不需要CSRF防护——只要是浏览器发起的请求(比如表单提交、AJAX请求),CSRF攻击就有可乘之机。通过Cookie存储CSRF Token、前端请求头携带Token的方式,能在无状态场景下有效完成CSRF校验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 19:01:52