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(); }
核心原因
- 自定义登录过滤器未处理CSRF校验:Spring Security默认的
UsernamePasswordAuthenticationFilter会自动集成CSRF校验逻辑,但你自定义的JwtUsernameAndPasswordAuthenticationFilter继承自AbstractAuthenticationProcessingFilter,默认不包含CSRF校验逻辑,导致登录请求绕过了CSRF校验环节(或校验失败后未正确抛出异常)。 - 过滤器执行顺序可能异常:如果自定义登录过滤器在
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
相关产品推荐
相关产品推荐

