Spring Security期望返回404却返回401的问题求助
问题根源
你的问题源于两个核心原因:
AntPathRequestMatcher的匹配逻辑与Spring MVC的路由规则存在差异,导致不存在的/hello/123请求未被正确匹配到permitAll规则,进而走到anyRequest().authenticated()触发401响应;- 即使请求被
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
相关产品推荐
相关产品推荐

