Spring Boot全局异常处理器未触发认证失败异常问题排查
问题原因及解决方案
核心问题1:异常类命名冲突
你自定义的AuthenticationException和Spring Security自带的org.springframework.security.core.AuthenticationException重名了。当Bearer Token无效时,Spring Security抛出的是自身的AuthenticationException,但你的全局异常处理器只监听你自定义的同名类,自然无法匹配触发。
核心问题2:过滤器链执行顺序限制
Spring Security的认证逻辑运行在DispatcherServlet之前的过滤器链中,默认@ControllerAdvice仅能捕获控制器层(@Controller/@RestController)抛出的异常,无法直接处理过滤器阶段的异常。
具体修复步骤
1. 重命名自定义异常类(避免冲突)
@ResponseStatus(HttpStatus.UNAUTHORIZED) public class CustomAuthenticationException extends RuntimeException { public CustomAuthenticationException(String message) { super(message); } }
2. 调整全局异常处理器,兼容Spring Security异常
修改处理器,同时支持处理Spring Security自带的认证异常和自定义异常:
@RestControllerAdvice public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { // 处理Spring Security原生认证异常 @ExceptionHandler(org.springframework.security.core.AuthenticationException.class) public ResponseEntity<ErrorResponse> handleSpringAuthException(org.springframework.security.core.AuthenticationException ex) { ErrorDetails errorDetails = new ErrorDetails( HttpStatus.UNAUTHORIZED.toString(), HttpStatus.UNAUTHORIZED.value(), ex.getMessage(), ex.getMessage(), new Date(), null ); return new ResponseEntity<>(new ErrorResponse(List.of(errorDetails)), HttpStatus.UNAUTHORIZED); } // 处理自定义认证异常(可选) @ExceptionHandler(CustomAuthenticationException.class) public ResponseEntity<ErrorResponse> handleCustomAuthException(CustomAuthenticationException ex) { ErrorDetails errorDetails = new ErrorDetails( HttpStatus.UNAUTHORIZED.toString(), HttpStatus.UNAUTHORIZED.value(), ex.getMessage(), ex.getMessage(), new Date(), null ); return new ResponseEntity<>(new ErrorResponse(List.of(errorDetails)), HttpStatus.UNAUTHORIZED); } }
3. 修改认证入口点,将异常转发至DispatcherServlet
通过转发到/error端点,让DispatcherServlet接管异常处理,从而触发全局异常处理器:
@Component public class AuthEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException authException) throws IOException, ServletException { // 将异常绑定到请求属性,供DispatcherServlet识别 request.setAttribute(DispatcherServlet.EXCEPTION_ATTRIBUTE, authException); // 转发到默认错误端点,触发全局异常处理器 request.getRequestDispatcher("/error").forward(request, response); } }
4. 确保Spring Security配置中启用自定义入口点
@Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private AuthEntryPoint authEntryPoint; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(Customizer.withDefaults()) .authenticationEntryPoint(authEntryPoint) // 绑定自定义入口点 ); return http.build(); } }
额外说明
- 若不需要自定义异常,可直接删除自己的
AuthenticationException类,仅保留处理Spring Security原生异常的处理器方法。 - Spring Boot 3.x中,
@RestControllerAdvice比@ControllerAdvice更适合处理REST接口的异常,无需额外配置@ResponseBody。
内容的提问来源于stack exchange,提问作者Arun
相关产品推荐
相关产品推荐

