AuthenticationException异常无法被全局异常捕获的解决办法
阅读原文时间:2023年08月23日阅读:3

我们可以先看一下为什么不能被捕获?

很明显JwtFilter的祖宗是Fliter,而我们自己定义的全局异常处理器@RestControllerAdvice

这个注解是 @ControllerAdvice@ResponseBody的结合体。

主要是针对的我们controller控制器的。而过滤器是在这个之前进行处理的。我们在Filter里面进行抛出异常,那么该怎么做呢?

@RestControllerAdvice
public class GlobalExceptionHandler {
    xxxxx
}

MyRealm域对象

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    //对传入的token进行类型转换
    MyJsonWebToken myJsonWebToken = (MyJsonWebToken) authenticationToken;
    String token = myJsonWebToken.getCredentials() + "";
    //直接通过redis进行判断
    RbacManagerDTO rbacManagerDTO = (RbacManagerDTO) redisTemplate.opsForValue().get(token);
    if (null != rbacManagerDTO) {
        return new SimpleAuthenticationInfo(token, token, "myRealm");
    } else {
        throw new AuthenticationException("token已过期,请重新登录");
    }
}

Jwt验证步骤

@SneakyThrows
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
    //检查认证请求,判断请求头中是否有token,有就执行登录验证
    if (isLoginAttempt(request, response)) {
        try {
            //执行登录
            executeLogin(request, response);
            //全局异常无法捕获filter里的异常,这里就使用请求转发给controller,返回给前端
        } catch (AuthenticationException e) {
            response401(request, response, e.getMessage());
        } catch (Exception e) {
            //如果没有token,那么就请求转发到到401请求,让410controller返回前端一个请求
            response401(request, response, "其他异常");
        }
    } else {
        //没有token
        response401(request, response, "没有token");
    }
    return true;
}

具体实现response401()方法

private void response401(ServletRequest request, ServletResponse response
        , String msg) throws ServletException, IOException {
    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    try {
        // //请求转发401controller
        httpServletRequest.getRequestDispatcher("/rbacManager/401/" + msg).forward(request, response);
    } catch (ServletException | IOException e) {
        e.printStackTrace();
    }
}

401专属controller

@GetMapping("/401/{msg}")
public ResponseResult error (@PathVariable("msg") String msg){
    return new ResponseResult(400,msg,null);
}

这样前台就可以收到我们的状态了。而我们的域对象的异常也算是成功返回给前端了。ヾ(✿゚▽゚)ノ

结果展示: