在使用Spring Security时用过滤器进行jwt校验时,全局的异常返回没有捕获到Filter中的异常。特此记录一下
原因:在Spring Boot
由于全局异常处理@RestControllerAdvice
只会去捕获所有Controller
层抛出的异常,所以在filter当中抛出的异常异常类是没有感知的。
解决办法 :在过滤器中将异常转移到Controller中
在过滤器中注入HandlerExceptionResolver
然后通过resolver.resolveException()
将异常转移到Controller即可:
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
完整Filter代码如下:
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Resource
private RedisUtil redisUtil;
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 获取token
String token = request.getHeader("token");
// 如果请求头中不包含token直接放行
if (StringUtils.isBlank(token)) {
filterChain.doFilter(request, response);
return;
}
// 解析token
String userId = null;
try {
Claims claims = JwtUtil.parseJWT(token);
userId = claims.getSubject();
} catch (BaseException e) {
log.error("非法的token:{}", token);
//throw new BaseException(ResultCode.TOKEN_VALIDATE_LOSE);
resolver.resolveException(request, response, null, new BaseException(ResultCode.TOKEN_VALIDATE_LOSE));
return;
}
// 从redis中获取用户信息
String redisKey = "login:" + userId;
LoginUser loginUser = (LoginUser) redisUtil.get(redisKey);
if (Objects.isNull(loginUser)) {
//throw new BaseException(10007, "用户未登录");
// 交给全局异常处理类处理
resolver.resolveException(request, response, null, new BaseException(10007, "用户未登录"));
return;
}
// 存入SecurityContextHolder
// loginUser.getAuthorities()获取权限信息封装到Authentication
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
// 放行
filterChain.doFilter(request, response);
}
}
自定义异常类:
@EqualsAndHashCode(callSuper = true)
@Data
public class BaseException extends RuntimeException {
private static final long serialVersionUID = 7939259259170410861L;
//错误代码
private Integer code;
// 错误信息
private String message;
public BaseException() {
super();
}
public BaseException(ResultCode resultCode) {
super(resultCode.getMessage());
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
}
public BaseException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
全局捕获异常类:
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(value = BaseException.class)
public ResponseResult<String> baseExceptionHandler(BaseException e) {
String s = CommonUtils.exceptionInfo(e);
log.error("发生业务异常!异常处在:[{}] , 原因是:[{}]", s, e.getMessage());
return new ResponseResult<>(e.getCode(), e.getMessage());
}
@ExceptionHandler(value = NullPointerException.class)
public ResponseResult<String> exceptionHandler(NullPointerException e) {
String s = CommonUtils.exceptionInfo(e);
log.error("发生空指针异常!异常处在:[{}] , 原因是:[{}]", s, e.getMessage());
return new ResponseResult<>(ResultCode.BODY_NOT_MATCH);
}
@ExceptionHandler(value = Exception.class)
public ResponseResult<String> exceptionHandler(Exception e) {
String s = CommonUtils.exceptionInfo(e);
log.error("未知异常!异常处在:[{}] , 原因是:[{}]", s, e.getMessage());
return new ResponseResult<>(ResultCode.INTERNAL_SERVER_ERROR.getCode(), e.getMessage());
}