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

Spring Boot3中SecurityFilterChain API请求匹配器配置异常排查

解决方案

问题出在Spring Security对API路径的异常处理逻辑上——你给/api/**开了permitAll,但当API密钥校验失败抛出异常时,Spring Security还是用了默认的网页端认证入口(跳登录页),而不是返回JSON错误。要解决这个,得给API路径单独配置异常处理规则,同时确保过滤器位置正确。

1. 编写返回JSON格式的认证异常处理器

先实现一个自定义的AuthenticationEntryPoint,专门处理API请求的未授权场景:

@Component
public class ApiAuthEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        // 用Jackson将错误信息序列化为JSON输出
        new ObjectMapper().writeValue(response.getOutputStream(), 
            Map.of("code", 401, "message", "API密钥缺失或无效")
        );
    }
}

2. 配置SecurityFilterChain时区分API与网页路径

有两种配置方式,任选其一即可:

方式一:拆分两个独立的安全过滤器链

分别对API路径和普通网页路径做针对性配置:

@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http, ApiAuthEntryPoint apiEntryPoint) throws Exception {
    http
        .securityMatcher("/api/**") // 仅匹配API路径
        .authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
        .exceptionHandling(ex -> ex.authenticationEntryPoint(apiEntryPoint)) // 指定API专属异常处理器
        .addFilterBefore(你的API密钥过滤器实例, UsernamePasswordAuthenticationFilter.class) // 将API密钥过滤器放在Spring Security认证过滤器之前
        .csrf(csrf -> csrf.disable()); // API场景通常不需要CSRF保护

    return http.build();
}

@Bean
public SecurityFilterChain webSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .securityMatcher("/**") // 匹配所有非API的网页路径
        .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
        .formLogin(form -> form.loginPage("/login").permitAll());

    return http.build();
}

方式二:在同一个过滤器链中绑定路径专属异常处理器

如果不想拆分链,也可以在同一个配置里给API路径单独指定异常处理逻辑:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, ApiAuthEntryPoint apiEntryPoint) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/**").permitAll()
            .anyRequest().authenticated()
        )
        .exceptionHandling(ex -> ex
            // 为/api/**路径绑定专属的异常处理器
            .defaultAuthenticationEntryPointFor(apiEntryPoint, new AntPathRequestMatcher("/api/**"))
        )
        .addFilterBefore(你的API密钥过滤器实例, UsernamePasswordAuthenticationFilter.class)
        .csrf(csrf -> csrf.ignoringRequestMatchers("/api/**")) // 忽略API路径的CSRF检查
        .formLogin(form -> form.loginPage("/login").permitAll());

    return http.build();
}

核心原理

当你仅给/api/**设置permitAll时,Spring Security的默认异常处理器依然会接管认证失败的请求(跳转登录页)。通过给API路径绑定专属的AuthenticationEntryPoint,可以让这类请求返回JSON格式的401错误,同时保证网页请求依然遵循正常的登录跳转逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 21:55:15