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

配置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没有被配置为允许匿名访问。从日志流程可以看到:

  1. DispatcherServlet处理请求后已经生成了400响应
  2. 系统会自动转发请求到/error端点来统一处理错误响应
  3. 但/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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:17:03