Spring Boot 3中Oauth2ResourceServer自定义认证异常处理问题
解决Spring Boot 3 OAuth2资源服务器自定义AuthenticationManagerResolver异常传递问题
核心原因
自定义AuthenticationManagerResolver抛出的异常发生在Filter认证阶段,早于Spring MVC的DispatcherServlet执行,因此无法被@RestControllerAdvice直接捕获。默认的AuthenticationEntryPoint会覆盖原始异常,返回通用的InsufficientAuthenticationException,且无法自动获取MVC的HandlerExceptionResolver。
解决方案
通过自定义AuthenticationEntryPoint将原始异常委托给MVC的异常处理器,让@RestControllerAdvice能捕获并处理原始异常信息。
1. 自定义AuthenticationEntryPoint
注入MVC的HandlerExceptionResolver,将原始异常传递给MVC异常处理链:
@Component public class CustomAuthEntryPoint implements AuthenticationEntryPoint { private final HandlerExceptionResolver exceptionResolver; // 主动注入HandlerExceptionResolver,解决默认null问题 @Autowired public CustomAuthEntryPoint(HandlerExceptionResolver exceptionResolver) { this.exceptionResolver = exceptionResolver; } @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { // 将原始异常存入请求属性,便于后续处理器获取 request.setAttribute("javax.servlet.error.exception", authException); // 委托给MVC异常处理器处理 exceptionResolver.resolveException(request, response, null, authException); } }
2. 配置SecurityFilterChain
将自定义的AuthenticationEntryPoint绑定到OAuth2资源服务器配置:
@Configuration @EnableWebSecurity public class SecurityConfig { private final CustomAuthEntryPoint customAuthEntryPoint; private final AuthenticationManagerResolver<HttpServletRequest> customAuthManagerResolver; @Autowired public SecurityConfig(CustomAuthEntryPoint customAuthEntryPoint, AuthenticationManagerResolver<HttpServletRequest> customAuthManagerResolver) { this.customAuthEntryPoint = customAuthEntryPoint; this.customAuthManagerResolver = customAuthManagerResolver; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .oauth2ResourceServer(oauth2 -> oauth2 .authenticationManagerResolver(customAuthManagerResolver) .authenticationEntryPoint(customAuthEntryPoint) ) .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint(customAuthEntryPoint) ); return http.build(); } }
3. 在@RestControllerAdvice中处理原始异常
直接捕获自定义认证异常或AuthenticationException,返回带原始消息的响应:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler({CustomAuthException.class, AuthenticationException.class}) public ResponseEntity<ErrorResponse> handleAuthExceptions(AuthenticationException ex) { ErrorResponse error = new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), ex.getMessage()); return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED); } // 自定义错误响应体 static class ErrorResponse { private int status; private String message; public ErrorResponse(int status, String message) { this.status = status; this.message = message; } // getter和setter省略 } }
4. 自定义认证异常(可选)
如果需要抛出业务相关的认证异常,继承AuthenticationException确保被Spring Security正确捕获:
public class CustomAuthException extends AuthenticationException { public CustomAuthException(String msg) { super(msg); } }
在AuthenticationManagerResolver中抛出该异常:
@Component public class CustomAuthManagerResolver implements AuthenticationManagerResolver<HttpServletRequest> { @Override public AuthenticationManager resolve(HttpServletRequest request) { String authType = request.getHeader("X-Auth-Type"); if (!"VALID_TYPE".equals(authType)) { throw new CustomAuthException("不支持的认证类型:" + authType); } // 返回对应AuthenticationManager逻辑 return authentication -> authentication; } }
内容的提问来源于stack exchange,提问作者Tomas Lukac
相关产品推荐
相关产品推荐

