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

Spring Boot 3.4.0中Spring Security返回403问题的调整需求

问题分析

当前遇到两个核心问题:

  1. 未认证请求非白名单接口时,Spring Security默认返回403而非预期的401;
  2. 请求不存在的接口时,Security先拦截触发认证检查,返回403而非Spring MVC的404。

解决方案

1. 自定义未认证返回401

通过配置AuthenticationEntryPoint,覆盖Security默认的未认证处理逻辑,直接返回401状态码及自定义响应。

2. 让不存在的接口返回404

推荐两种实现方式:

  • 方式一(简洁高效):限制Security仅拦截特定前缀的接口(如/api/**),非该前缀的请求直接由Spring MVC处理,不存在时自然返回404;
  • 方式二(灵活适配):在AuthenticationEntryPoint中判断请求是否存在对应的处理器,无处理器则返回404。

修改后的完整配置代码

@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig {
    public static final String[] WHITE_LIST = {
            "/api/auth/**",
            "/api/public/**",
            "/v2/api-docs",
            "/swagger-resources/**",
            "/swagger-ui.html",
            "/hello"
    };

    private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtFilter jwtFilter) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                // 仅拦截/api开头的请求,其他请求直接由Spring MVC处理
                .securityMatcher("/api/**")
                .authorizeHttpRequests(auth -> {
                    auth.requestMatchers(WHITE_LIST).permitAll();
                    auth.anyRequest().authenticated();
                })
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                .exceptionHandling(exception ->
                        exception.authenticationEntryPoint((request, response, authException) -> {
                            // 未认证时返回401及自定义JSON响应
                            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                            String jsonResponse = "{\"code\":401,\"message\":\"未授权访问,请先登录\"}";
                            response.getWriter().write(jsonResponse);
                        })
                )
                .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        log.info("Created Password Encoder");
        return new BCryptPasswordEncoder();
    }
}

方式二(适配全路径场景)

如果你的接口没有统一前缀,可以用以下方式在AuthenticationEntryPoint中区分404和401:

.exceptionHandling(exception ->
        exception.authenticationEntryPoint((request, response, authException) -> {
            // 检查请求是否有对应的处理器
            HandlerExecutionChain handler = request.getAttribute(DispatcherServlet.EXECUTION_CHAIN_ATTRIBUTE);
            if (handler == null || handler.getHandler() == null) {
                // 无处理器,返回404
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                String jsonResponse = "{\"code\":404,\"message\":\"接口不存在\"}";
                response.getWriter().write(jsonResponse);
            } else {
                // 有处理器但未认证,返回401
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                String jsonResponse = "{\"code\":401,\"message\":\"未授权访问,请先登录\"}";
                response.getWriter().write(jsonResponse);
            }
        })
)

内容的提问来源于stack exchange,提问作者Nguyen Manh Cuong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 17:52:42