You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot配置requestMatchers.permitAll()仍返回403错误排查求助

Spring Boot配置requestMatchers.permitAll()仍返回403错误排查求助

我太懂你这种抓耳挠腮的感觉了——明明在SecurityConfig里给/api/user/test配置了permitAll,结果还是硬返回403,只能靠关掉整个Spring Security或者把所有请求设为permitAll才能绕过去,这搁谁都得崩溃。我对着你的代码和Debug日志捋了一圈,帮你梳理几个大概率的问题点,你可以挨个排查:

1. 跨域预检请求(OPTIONS)被拦截了

这绝对是踩坑率最高的情况!如果你的请求是从前端页面发过来的,浏览器会先偷偷发一个OPTIONS方法的预检请求,而你现在的SecurityConfig里只给POST方法的/api/user/test开了permitAll,OPTIONS请求根本匹配不上这个规则,直接撞到anyRequest().authenticated()上,可不就返回403了嘛!

解决方法很简单,要么给这个路径开放所有HTTP方法,要么单独给OPTIONS请求开绿灯:

// 方法一:允许/api/user/test的所有HTTP方法(包括预检请求)
.requestMatchers("/api/user/test").permitAll()

// 方法二:单独放行OPTIONS,同时保留POST的permitAll
.requestMatchers(HttpMethod.OPTIONS, "/api/user/test").permitAll()
.requestMatchers(HttpMethod.POST, "/api/user/test").permitAll()

另外建议顺便把跨域配置加上,避免后续再踩同类坑:

http.cors(cors -> cors.configurationSource(corsConfigurationSource()))

// 自定义跨域规则(示例,替换成你的前端域名)
private CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
    config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
    config.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}

2. 路径匹配不精确

你得仔细核对实际发起的请求路径和配置的路径是不是完全一致:

  • 有没有多/少了末尾斜杠?比如你请求的是/api/user/test/(带尾巴斜杠),但配置的是/api/user/test,这会导致匹配失败;
  • 有没有带额外的路径参数?比如请求的是/api/user/test/123,但你配置的是精确匹配/api/user/test,自然也匹配不上。

如果是需要前缀匹配的场景,你可以用/api/user/test/**来覆盖子路径,但你的情况是精确匹配,所以务必保证请求路径和配置的完全一致。

3. 自定义JWT过滤器的隐性干扰

看你的JWTAuthenticationFilter代码,虽然定义了PERMIT_ALL_PREFIXES列表,但实际逻辑里并没有用它来判断是否跳过token校验?不过当前的逻辑是对的:只要有Bearer token就校验,没有或无效就直接放行filterChain。

不过你可以检查下:有没有可能之前测试时没注释掉response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)那段代码,导致response被提前设为401,后续又被Spring Security转为403?虽然你现在注释掉了,但还是可以确认下过滤器里有没有其他修改response的逻辑。

4. 匿名认证被无意禁用

Spring Security默认是开启匿名认证的,但如果你的配置里不小心加了http.anonymous(AnonymousConfigurer::disable),那哪怕是permitAll路径,匿名请求也会被直接拒绝返回403。看你的SecurityConfig里没有这个配置,这个可能性比较低,但可以顺手确认下。

最后给你一个调整后的参考配置

我把跨域、OPTIONS处理、认证入口点都加上了,你可以试试:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(CsrfConfigurer::disable)
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/user/test").permitAll()
                        .requestMatchers("/error").permitAll()
                        .anyRequest().authenticated()
                )
                // 显式开启匿名认证,确保permitAll路径能正常接受匿名请求
                .anonymous(anonymous -> anonymous.authorities("ROLE_ANONYMOUS"))
                // 配置认证入口点,非permitAll请求返回401而非403,更符合语义
                .exceptionHandling(ex -> ex
                        .authenticationEntryPoint((request, response, authException) -> {
                            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: 无效或缺失JWT令牌");
                        })
                )
                .addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    private CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(Arrays.asList("http://localhost:3000")); // 替换为你的前端域名
        config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
        config.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}

如果排查完这些还是不行,你可以把请求的具体信息(比如实际请求方法、完整路径、请求头)贴出来,再进一步定位问题。

内容来源于stack exchange

火山引擎 最新活动