SpringBoot 3.1.0升级后控制器报错返回401而非500问题求助
问题描述
我近期将SpringBoot从2.7.4版本迁移至3.1.0版本,因部分类已废弃,对Security配置进行了修改。目前所有功能正常,但Spring应用控制器中抛出的任何错误都无法返回给调用方,响应始终为401 Unauthorized。即使是标记为忽略的端点,在发生异常时也会返回401。此前版本中会正常返回500 INTERNAL_SERVER_ERROR,不确定该提供哪些文件,恳请帮助。
相关代码
SecurityConfig类
@EnableWebSecurity @Configuration public class SecurityConfig { @Value( "${auth0.audience}" ) private String audience; @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String issuer; @Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring().requestMatchers("/v1/noauth/**", "/actuator/**"); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authz) -> authz .requestMatchers("/v1/**").authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 .jwt((jwt) -> jwt .decoder(jwtDecoder()) ) ) .cors(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable); return http.build(); } @Bean JwtDecoder jwtDecoder() { /* By default, Spring Security does not validate the "aud" claim of the token, to ensure that this token is indeed intended for our app. Adding our own validator is easy to do: */ NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer); OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience); OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer); OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator); jwtDecoder.setJwtValidator(withAudience); return jwtDecoder; } }
Slf4jMDCFilter类(RequestId配置过滤器)
@Data @EqualsAndHashCode(callSuper = false) public class Slf4jMDCFilter extends OncePerRequestFilter { private final String responseHeader; private final String mdcTokenKey; private final String requestHeader; public Slf4jMDCFilter(String responseHeader, String mdcTokenKey, String requestHeader){ this.responseHeader = responseHeader; this.mdcTokenKey = mdcTokenKey; this.requestHeader = requestHeader; } @Override protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws java.io.IOException, ServletException { try { final String token; if (StringUtils.hasText(requestHeader) && StringUtils.hasText(request.getHeader(requestHeader))) { token = URLEncoder.encode(request.getHeader(requestHeader)); } else { token = UUID.randomUUID().toString().toUpperCase(); } MDC.put(mdcTokenKey, token); if (StringUtils.hasText(responseHeader)) { response.addHeader(responseHeader, token); } chain.doFilter(request, response); } finally { MDC.remove(mdcTokenKey); } } }
Slf4jMDCFilterConfiguration类(过滤器配置类)
@Configuration public class Slf4jMDCFilterConfiguration { public static final String DEFAULT_RESPONSE_TOKEN_HEADER = "ResponseToken"; private final String responseHeader = DEFAULT_RESPONSE_TOKEN_HEADER; private final String mdcTokenKey = Util.DEFAULT_MDC_UUID_TOKEN_KEY(); @Value( "${config.slf4jfilter.requestHeader}" ) private String requestHeader; @Bean public FilterRegistrationBean servletRegistrationBean() { final FilterRegistrationBean registrationBean = new FilterRegistrationBean(); final Slf4jMDCFilter log4jMDCFilterFilter = new Slf4jMDCFilter(responseHeader, mdcTokenKey, requestHeader); registrationBean.setFilter(log4jMDCFilterFilter); registrationBean.setOrder(2); return registrationBean; } }
解决方案
问题根源
Spring Boot 3.x(对应Spring Security 6.x)调整了OAuth2资源服务器的异常处理逻辑:
- 默认情况下,所有流经OAuth2过滤器链的请求,未捕获的异常都会被统一转成401响应,覆盖了控制器原本应该返回的500错误
WebSecurity.ignoring()的规则会跳过所有Spring Security过滤器,包括异常处理机制,导致忽略端点的异常也无法被Spring MVC正常处理
修复步骤
1. 调整Security配置,统一异常处理逻辑
替换原有SecurityFilterChain配置,把忽略端点改用permitAll()声明,并添加自定义异常处理规则:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authz) -> authz // 用permitAll替代WebSecurity.ignoring(),让请求经过完整过滤器链 .requestMatchers("/v1/noauth/**", "/actuator/**").permitAll() .requestMatchers("/v1/**").authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 .jwt((jwt) -> jwt.decoder(jwtDecoder())) // 仅对认证失败的情况返回401 .authenticationEntryPoint((request, response, authException) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage()); }) ) .exceptionHandling(exceptions -> exceptions // 权限不足返回403 .accessDeniedHandler((request, response, ex) -> { response.sendError(HttpServletResponse.SC_FORBIDDEN, ex.getMessage()); }) // 已授权端点的异常,交给Spring MVC的错误处理机制处理 .defaultAuthenticationEntryPointFor((request, response, ex) -> { request.getRequestDispatcher("/error").forward(request, response); }, request -> request.getRequestURI().startsWith("/v1/")) ) .cors(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable); return http.build(); }
同时删除原有的WebSecurityCustomizer Bean,避免规则冲突。
2. 添加全局异常处理器(可选但推荐)
创建全局异常处理器,统一格式化控制器抛出的异常响应:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex, HttpServletRequest request) { ErrorResponse error = new ErrorResponse( HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage(), request.getRequestURI(), LocalDateTime.now() ); return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); } // 可根据业务需求添加更多特定异常的处理方法 } // 定义统一的错误响应体 @Data @AllArgsConstructor class ErrorResponse { private int status; private String message; private String path; private LocalDateTime timestamp; }
3. 调整过滤器顺序
确保Slf4jMDCFilter在Security过滤器之前执行,避免影响异常处理:
@Bean public FilterRegistrationBean servletRegistrationBean() { final FilterRegistrationBean registrationBean = new FilterRegistrationBean(); final Slf4jMDCFilter log4jMDCFilterFilter = new Slf4jMDCFilter(responseHeader, mdcTokenKey, requestHeader); registrationBean.setFilter(log4jMDCFilterFilter); // 设置优先级为最高优先级+1,确保在Security过滤器之前执行 registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); return registrationBean; }
验证场景
修改完成后,测试以下场景确认修复效果:
- 访问
/v1/noauth/**端点并抛出异常,应返回500状态码及自定义错误响应 - 访问
/v1/**端点携带无效Token,应返回401 - 访问
/v1/**端点携带有效Token但控制器抛出异常,应返回500状态码及自定义错误响应
内容的提问来源于stack exchange,提问作者asds_asds
相关产品推荐
相关产品推荐

