自定义的SpringSecurity异常一直被全局异常捕获或者SpringSecurity异常抛出不了问题;UserNotFoundException 不抛出问题
问题描述
在项目中自定义的SpringSecurity异常不会正常执行,而是会被全局异常捕获到。解决完SpringSecurity异常被全局异常捕获的bug之后,轮到UserNotFoundException 异常一直捕获不到
问题分析
- 现象:当存在全局异常处理器的时候,自定义的SpringSecurity异常拦截器处理时效,当移除全局异常处理器时,自定义的SpringSecurity异常拦截器正常启动。
 - 结论:全局异常处理器会干扰到SpringSecurity的异常处理流程,导致自定义的处理器无法按预期执行。问题出现在SpringSecurity异常处理和转换的过滤器 ExceptionTranslatonFilter 的 doFilter 方法。
 

解决方案
- 为了确保异常能够传递给 Spring Security 的自定义异常处理器,你可以对全局异常处理器(
GlobalExceptionHandler)进行修改。如果异常是AuthenticationException或AccessDeniedException,则继续将其抛出以便交给自定义处理器处理。 - 代码如下
 

注意:导入的包一定不能导入错误,不然抛出的异常会不匹配,还是导致SpringSecurity异常捕获不到。
import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.AuthenticationException;
并且在判断的时候最好是如下语句:
// 意思是AccessDeniedException异常及其子类和AuthenticationException异常的子类都能被接收,不然之后UserDetial抛出的 UserNotFoundException 异常捕获不到 if (AccessDeniedException.class.isInstance(e) || AuthenticationException.class.isInstance(e))
完整代码如下:
@RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 处理自定义业务异常 SystemException */ @ExceptionHandler(SystemException.class) public ResponseResult systemExceptionHandler(SystemException e) { log.error("【业务异常】错误码:{},错误信息:{}", e.getCode(), e.getMsg(), e); return ResponseResult.errorResult(e.getCode(), e.getMsg()); } /** * 处理其他所有未捕获的异常(兜底) */ @ExceptionHandler(Exception.class) public ResponseResult defaultExceptionHandler(Exception e) throws Exception { log.error("【未知异常】{}", e.getMessage(), e); System.out.println(e.getClass()); //抛出AccessDeniedException异常 // 将 Spring Security 异常继续抛出,以便交给自定义处理器处理AuthenticationException if (AccessDeniedException.class.isInstance(e) || AuthenticationException.class.isInstance(e)) { throw e; } return ResponseResult.errorResult(AppHttpCodeEnum.INTERNAL_SERVER_ERROR); } // 处理参数校验异常 @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseResult handleValidationExceptions(MethodArgumentNotValidException ex) { String errorMessages = ex.getBindingResult() .getAllErrors() .stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.joining(", ")); return ResponseResult.errorResult(AppHttpCodeEnum.VALIDATION_FAILED.getCode(), errorMessages); } }
/** * 实现了 AccessDeniedHandler 接口,用于处理 用户已经登录,但没有访问某个资源的权限时的异常处理逻辑 。 */ @Component @Slf4j public class AccessDeniedHandlerImpl implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { accessDeniedException.printStackTrace(); log.info("AccessDeniedHandler 处理异常: {}", accessDeniedException.getMessage()); ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH); //响应给前端 // String json = JsonUtils.writeValueAsString(result); ResponseUtils.outJson(response, result); } }
@Component @Slf4j public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { // authException.printStackTrace(); //InsufficientAuthenticationException //BadCredentialsException ResponseResult result = null; //对象的类型判断,准确判断是什么类型(authException instanceof BadCredentialsException),并在全响应中处理 if(authException instanceof UsernameNotFoundException || authException instanceof BadCredentialsException){ // authException.getMessage() 的结果是 “用户名或密码错误" log.info("AuthenticationEntryPoint 处理异常: {}", authException.getMessage()); result = ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_ERROR); } else if(authException instanceof InsufficientAuthenticationException){ log.info("AuthenticationEntryPoint 处理异常: {}", authException.getMessage()); result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); } else if(authException instanceof InternalAuthenticationServiceException){ log.info("AuthenticationEntryPoint 处理异常: {}", authException.getMessage()); result = ResponseResult.errorResult(AppHttpCodeEnum.ACCOUNT_DISABLED); } else{ log.info("AuthenticationEntryPoint 处理异常: {}", authException.getMessage()); result = ResponseResult.errorResult(AppHttpCodeEnum.UNAUTHORIZED.getCode(),AppHttpCodeEnum.UNAUTHORIZED.getMsg()); } //响应给前端 // String json = JsonUtils.writeValueAsString(result); ResponseUtils.outJson(response,result); } }
解决完上面的问题之后,出现UserNotFoundException 异常一直捕获不到
- UserNotFoundException异常的意思是,用户名错误 异常。
 
代码如下:
public class UserDetailServiceImpl implements UserDetailsService

经过实践,断点之后得到结论,就是因为上面出现的异常会被一直认为是 BadCredentialsException 异常(“message是 用户名或密码错误”)。也就是说 UserNotFoundException 不可能一直被单独捕获到。
- 解决方法
 
参考文章:
                    
                
                
            
        
浙公网安备 33010602011771号