如何让Spring Security优先捕获AuthenticationException而非ControllerAdvice?
解决ControllerAdvice优先捕获AuthenticationException的问题
核心原因
你的AuthenticationException是在**DispatcherServlet处理请求的阶段(比如Controller层)**抛出的,而非Spring Security过滤器链阶段,所以会被@ControllerAdvice先捕获。如果异常是在过滤器链抛出,@ControllerAdvice根本不会触及。
可行解决方案
1. 在全局异常处理器中排除AuthenticationException处理
直接在@ControllerAdvice的异常处理逻辑里,对AuthenticationException不做处理,重新抛出交给Spring Security的commence方法:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<Object> handleGlobalException(Exception ex, WebRequest request) { // 遇到AuthenticationException直接抛出,交给Spring Security处理 if (ex instanceof AuthenticationException) { throw (AuthenticationException) ex; } // 其他异常的常规处理逻辑 ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR); } }
2. 让认证逻辑在Spring Security过滤器链中执行
如果你的认证是手动在Controller里调用AuthenticationManager.authenticate()触发的,改成由Spring Security的过滤器(比如UsernamePasswordAuthenticationFilter)来处理认证。这样AuthenticationException会在过滤器链阶段抛出,此时DispatcherServlet还未介入,@ControllerAdvice无法捕获,自然会被ExceptionTranslationFilter的commence方法处理。
3. 细化@ExceptionHandler的异常范围
如果全局异常处理器不需要处理所有Exception,可以缩小@ExceptionHandler的捕获范围,直接不包含AuthenticationException:
@ControllerAdvice public class GlobalExceptionHandler { // 只处理指定类型的异常,排除AuthenticationException @ExceptionHandler(value = {IllegalArgumentException.class, NullPointerException.class}) public ResponseEntity<Object> handleSpecificExceptions(Exception ex, WebRequest request) { // 异常处理逻辑 ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST); } }
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

