问题描述
配置Realm之后,发现在Realm中抛出的异常被无法捕获,最后抛出AuthenticationException异常,返回的是默认异常json格式,无法自定义选择code
原因分析
AuthenticationException 异常时Shiro内部进行抛出的,全局异常捕获器在 Filter 之后执行,不能正常进行补捕获,只能在 Filter内部进行处理。
解决方案
项目内部集成shiro时,自定义Filter继承了BasicHttpAuthenticationFilter重写 onAccessDenied 方法。在onAccessDenied 方法中我们可以返回我们需要的 json 数据,也可以记录日志执行我们自己的方法。这里返回的数据是我自定义的Result 类,里面包含了错误码和错误信息。
认证失败是我们的业务逻辑的错误而不是网络请求的错误,所以我们把HTTP的状态码设置成了 200 ,通过我们自己定义的Result来返回实际的错误信息。
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) {
try {
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpRequest = (HttpServletRequest) request;
httpResponse.setStatus(200);
httpResponse.setContentType("application/json;charset=utf-8");
//解决跨域问题
if ("OPTIONS".equals(httpRequest.getMethod())) {
httpResponse.setStatus(HttpServletResponse.SC_NO_CONTENT);
return true;
}
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}catch (IOException e) {
e.printStackTrace();
}
return false;
配置到这没有结束,这里配置了后只是为了让在下面的配置生效。
重写登录认证的时候进行返回结果集的处理,通过ServletResponse 返回统一的结果集 。
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
try {
executeLogin(request, response);
return true;
} catch (Exception e) {
/*自定义返回结果集*/
try {
if(e.getCause() instanceof BuyPackageException){
response.setContentType("application/json;charset=UTF-8");
response.getWriter().print(JSON.toJSONString( Result.error(1006,e.getCause().getMessage())));
}else {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().print(JSON.toJSONString(Result.error(1005, e.getMessage())));
}
} catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
}
重写了isAccessAllowed和onAccessDenied后返回的显示结果就会如下所示
{
"code": 1005,
"exception": "org.apache.shiro.authc.AuthenticationException",
"message": "前端的租户信息与后台设置的主租户不一致,请重新登录",
"success": false,
"timestamp": 1698974976351
}
原理分析
我个人认为是onAccessDenied方法中将所有被拦截的500的Internal Server Error 转成了可通过的200后,isAccessAllowed方法中写入的返回才得以生效,具体的原理未知。