Spring Security中AuthenticationEntryPoint与@ControllerAdvice共存问题咨询
问题原因
@ControllerAdvice默认会捕获所有Spring容器中抛出的Exception类型异常,而Spring Security的认证相关异常(AuthenticationException、AccessDeniedException等)是在请求到达Controller之前的过滤器链阶段抛出的,你当前配置的全局异常处理器捕获了所有Exception,会覆盖掉AuthenticationEntryPoint的处理逻辑。
解决方案
你可以任选以下任意一种方式实现两者共存:
方案1:全局异常处理器排除Security相关异常
修改你的ExceptionControllerAdvice,在处理全局异常前判断异常类型,如果是Spring Security相关的认证/鉴权异常,直接抛出,交给AuthenticationEntryPoint处理即可,代码示例:
import org.springframework.security.core.AuthenticationException; import org.springframework.security.access.AccessDeniedException; @ControllerAdvice public class ExceptionControllerAdvice { private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionControllerAdvice.class); /**** 500 Entity */ @ExceptionHandler(value = Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public final ErrorDetail handleAllExceptions(Exception ex) throws Exception { // 排除Spring Security认证、鉴权异常,交给Security的异常处理器处理 if (ex instanceof AuthenticationException || ex instanceof AccessDeniedException) { throw ex; } LOGGER.error("An unexpected error occurred", ex); ErrorDetail problem = new ErrorDetail("Internal Error", "An unexpected error has occurred"); problem.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); return problem; } }
方案2:限定全局异常处理器仅处理Controller层异常
你可以给@ControllerAdvice指定作用范围,仅处理业务Controller抛出的异常,过滤器层的异常不会被捕获,自然会走Security的EntryPoint逻辑,示例:
// 仅捕获加了@RestController、@Controller注解的类抛出的异常 @ControllerAdvice(annotations = {RestController.class, Controller.class}) public class ExceptionControllerAdvice { // 原有逻辑保持不变 }
两种方案都不需要修改原有Security配置和EntryPoint逻辑,可直接兼容现有功能。
内容的提问来源于stack exchange,提问作者Evgeniy Skiba
相关产品推荐
相关产品推荐

