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

Spring Security期望返回404却返回401的问题求助

问题根源

你的问题源于两个核心原因:

  1. AntPathRequestMatcher的匹配逻辑与Spring MVC的路由规则存在差异,导致不存在的/hello/123请求未被正确匹配到permitAll规则,进而走到anyRequest().authenticated()触发401响应;
  2. 即使请求被permitAll允许,当DispatcherServlet找不到对应处理器时,你配置的HttpStatusEntryPoint会拦截后续异常并返回401,而非容器默认的404。

解决方案1:使用MvcRequestMatcher替代AntPathRequestMatcher

Spring Security 6.x官方推荐使用MvcRequestMatcher,它与Spring MVC的路由匹配逻辑完全一致,能确保所有符合/hello/**规则的请求都被正确识别。

修改你的SecurityConfiguration代码:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    private final MvcRequestMatcher.Builder mvcRequestMatcherBuilder;

    // 构造注入MvcRequestMatcher.Builder
    public SecurityConfiguration(MvcRequestMatcher.Builder mvcRequestMatcherBuilder) {
        this.mvcRequestMatcherBuilder = mvcRequestMatcherBuilder;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

        var anonymousRequestMatcher = new OrRequestMatcher(
                requestMatcher("/hello/**"),
                requestMatcher("/anonymous/**")
        );

        return httpSecurity
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(authorization ->
                        authorization
                                .requestMatchers(anonymousRequestMatcher).permitAll()
                                .anyRequest().authenticated())
                .exceptionHandling(exceptionHandling ->
                        exceptionHandling
                                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))
                .build();
    }

    private RequestMatcher requestMatcher(String pattern) {
        // 替换为MvcRequestMatcher,与Spring MVC路由逻辑一致
        return mvcRequestMatcherBuilder.pattern(pattern);
    }
}

解决方案2:自定义异常处理,优先返回404

如果坚持使用AntPathRequestMatcher,可通过配置Spring Boot抛出路径未找到异常,并自定义认证入口点处理该异常,返回404。

步骤1:配置Spring Boot抛出路径未找到异常

在application.properties中添加以下配置:

# 允许DispatcherServlet抛出NoHandlerFoundException
spring.mvc.throw-exception-if-no-handler-found=true
# 禁用静态资源映射,避免干扰路径匹配判断
spring.web.resources.add-mappings=false

步骤2:自定义AuthenticationEntryPoint

创建自定义入口点,判断异常类型,优先返回404:

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
    private final HttpStatusEntryPoint unauthorizedEntryPoint = new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED);

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        // 获取请求携带的异常信息
        Object exception = request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
        if (exception instanceof NoHandlerFoundException) {
            response.sendError(HttpStatus.NOT_FOUND.value(), "Resource not found");
            return;
        }
        // 其他未认证场景返回401
        unauthorizedEntryPoint.commence(request, response, authException);
    }
}

步骤3:替换Security配置中的认证入口点

修改SecurityConfiguration的异常处理逻辑:

.exceptionHandling(exceptionHandling ->
        exceptionHandling
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint()))

内容的提问来源于stack exchange,提问作者Phi Tiet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 22:13:15