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

Spring Security已禁用CSRF但开放端点仍返回401 Unauthorized且日志提示无效CSRF令牌

Spring Security已禁用CSRF但开放端点仍返回401 Unauthorized且日志提示无效CSRF令牌

看起来你遇到了个有点矛盾的棘手问题——明明已经禁用了CSRF防护,开放的端点却还是因为“无效CSRF令牌”返回401。我来帮你一步步排查可能的原因:

首先,确认CSRF禁用配置是否真的生效

日志里明确打出了“Invalid CSRF token”,说明Spring Security的CSRF过滤器还在工作,这意味着你的csrf().disable()可能没被正确应用。可以试试这些调整:

  1. 改用Lambda风格的CSRF配置
    旧的链式调用偶尔会因为顺序问题导致配置不生效,换成Lambda写法更稳妥:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable()) // 改用Lambda写法确保禁用生效
        .cors(cors -> cors.configurationSource(corsConfigurationSource()))
        .authorizeHttpRequests(auth -> auth
                .requestMatchers("/USERMANAGEMENT/user/add/**", "/login2", "/Logout**", "/refreshToken",
                        "/forgot/**", "/imgCategory/**", "/imgBank/**")
                .permitAll()
                .anyRequest().authenticated()
        )
        .exceptionHandling(ex -> ex.authenticationEntryPoint(authenticationEntryPoint))
        .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
    
    http.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);
    return http.build();
}
  1. 检查配置文件是否覆盖了代码设置
    如果你在application.properties或application.yml里配置了spring.security.csrf.enabled=true,这会直接覆盖代码中的禁用设置。赶紧检查一下配置文件,把这个配置删掉或者设为false。

  2. 确保当前Security配置优先级最高
    如果项目里有多个SecurityFilterChain,可能其他配置的优先级更高,导致你的CSRF禁用没生效。可以给你的SecurityFilterChain加上@Order(1)注解,确保它先被加载:

@Order(1)
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    // ... 你的配置内容
}

然后,验证开放端点的路径匹配是否正确

有时候401不是因为CSRF,而是请求路径没被permitAll匹配到:

  • 注意路径大小写:Spring Security的路径匹配默认区分大小写,比如你配置的是/USERMANAGEMENT/user/add/**,但请求的是/usermanagement/user/add(小写),就会匹配失败。可以尝试统一大小写,或者添加忽略大小写的配置:
.requestMatchers(AntPathRequestMatcher.antMatcher("/USERMANAGEMENT/user/add/**").caseSensitive(false),
                 "/login2", "/Logout**", ...)
.permitAll()
  • 明确指定请求方法:如果你的开放端点只接受POST请求,最好明确指定方法,避免因为请求方法不匹配导致的权限拦截:
.requestMatchers(HttpMethod.POST, "/USERMANAGEMENT/user/add/**", "/login2")
.permitAll()

最后,排查过滤器和认证入口点的干扰

你的JwtAuthenticationFilter会拦截所有请求,但正常情况下permitAll的端点即使没有token也应该允许访问。不过可以检查一下:

  • 你的JwtAuthenticationFilter在没有token的时候直接执行filterChain.doFilter,这部分逻辑是对的,不会抛出异常。
  • 如果AuthenticationEntryPoint被触发了,大概率是请求路径没匹配到permitAll,导致被判定为需要认证的资源。

额外小测试

可以临时注释掉http.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);这行代码,测试开放端点是否能正常访问。如果能访问,说明问题出在过滤器和权限配置的交互上;如果还是不行,那肯定是CSRF或路径匹配的问题。

备注:内容来源于stack exchange,提问作者Hendo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 08:48:08