配置Spring Security后HTTP状态码异常:应返回400却始终返回401
问题描述
我正在使用Spring Boot v3.2.3,引入了以下依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency>
我的Security配置如下:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(authorize -> authorize .requestMatchers("swagger-ui/**", "/v3/api-docs/**", "/send").permitAll() .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())); return http.build(); }
当前遇到的核心问题:无论请求本身触发何种错误,始终返回401状态码。
从日志来看,请求原本应该返回400 BAD_REQUEST:
2024-04-02T09:54:35.188+02:00 DEBUG 1930 --- [tpmc1000] [nio-8080-exec-1] o.s.web.method.HandlerMethod : Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<java.lang.Void> com.carrefour.fr.tpmc.controller.TransPelicanController.sendFile(com.carrefour.fr.tpmc.dto.FilePayload) throws com.carrefour.fr.tpmc.exception.FunctionalException: JSON parse error: Cannot deserialize value of type `byte[]` from String "": Unexpected end of base64-encoded String: base64 variant 'MIME-NO-LINEFEEDS' expects padding (one or more '=' characters) at the end. This Base64Variant might have been incorrectly configured 2024-04-02T09:54:35.189+02:00 WARN 1930 --- [tpmc1000] [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `byte[]` from String "": Unexpected end of base64-encoded String: base64 variant 'MIME-NO-LINEFEEDS' expects padding (one or more '=' characters) at the end. This Base64Variant might have been incorrectly configured] 2024-04-02T09:54:35.189+02:00 DEBUG 1930 --- [tpmc1000] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 400 BAD_REQUEST 2024-04-02T09:54:35.190+02:00 DEBUG 1930 --- [tpmc1000] [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2024-04-02T09:54:35.194+02:00 DEBUG 1930 --- [tpmc1000] [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing POST /error 2024-04-02T09:54:35.194+02:00 DEBUG 1930 --- [tpmc1000] [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2024-04-02T09:54:35.206+02:00 DEBUG 1930 --- [tpmc1000] [nio-8080-exec-1] o.s.s.w.s.HttpSessionRequestCache : Saved request http://localhost:8080/error?continue to session
即使抛出指定了400状态码的自定义异常,返回结果依然是401,自定义异常代码如下:
public FunctionalException(String message) { super(HttpStatus.BAD_REQUEST, message); }
问题根源及解决方案
问题出在Spring Boot默认的错误端点/error没有被配置为允许匿名访问。从日志流程可以看到:
- DispatcherServlet处理请求后已经生成了400响应
- 系统会自动转发请求到
/error端点来统一处理错误响应 - 但
/error不在你的permitAll列表中,Spring Security会拦截这个请求,要求认证,最终返回401
解决方法很直接,将/error路径加入到requestMatchers的permitAll规则中:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(authorize -> authorize .requestMatchers("swagger-ui/**", "/v3/api-docs/**", "/send", "/error").permitAll() .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())); return http.build(); }
修改后,/error端点可以被匿名访问,系统就能正确返回请求原本触发的错误状态码(比如400),而不会被Security拦截返回401。
内容的提问来源于stack exchange,提问作者Smaillns
相关产品推荐
相关产品推荐

