SpringSecurity的loadUserByUsername抛出异常无法捕获原因分析
SpringSecurity 相信大家对它都不陌生,这是一个令我又爱又恨的框架,配置不简单,但是功能却异常强大。下面我们就一起来分析一下loadUserByUsername 里抛出自定义异常无法捕获的原因吧
嗯,话不多说,自定义异常,全局异常处理拦截器、Security配置等我就不说了,直接上重点吧!
1、分析原因
首先我们在 loadUserByUsername 里抛出一个异常 ,为了演示,我直接在loadUserByUsername里抛出异常了
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (true){
throw new BusinessException(ResultCodeEnum.FAIL);
}
}
使用 postman 请求login接口
到后台查看,我抛出的异常直接被打印了,并没有被全局异常拦截器捕获,并且异常类也不是我抛出的,接下来我们debug查看
debug测试,好家伙,我终于找到了原因,原来在 DaoAuthenticationProvider 里就给我捕获了,还给我换成了其他的异常,可是明明是捕获了,为什么会打印了,继续查看
原来在doFilter里捕获并且打印了
2、解决方式
好了,原因我们找到了,那么怎么解决呢?我想到了两种方法
2.1、方式一
第一种,前后端分离模式,在登入失败的handler里处理,如下。
1、我们其实可以在security失败的handler里取得InternalAuthenticationServiceException异常,查看源码可以发现它是AuthenticationException异常的子类
2、刚刚查看源码其实我们就发现抛出 InternalAuthenticationServiceException 异常,并没有改变我们抛出的异常,而是把我们抛出的异常传递给它了,所以我们只需要取出来(ex)就好了
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
ErrorResult result = null;
//抛出的异常
if (e instanceof InternalAuthenticationServiceException){
InternalAuthenticationServiceException exception = (InternalAuthenticationServiceException) e;
if (exception.getCause()!=null) {
//判断抛出的是否是自己定义的异常
if (exception.getCause() instanceof BusinessException){
//自定义异常
BusinessException businessException= (BusinessException) exception.getCause();
result = ErrorResult.failure(businessException,request, HttpStatus.OK);
}else {
//用户不存在
result=ErrorResult.failure(ResultCodeEnum.USER_ACCOUNT_NOT_EXIST,request,HttpStatus.OK);
}
}else {
// 返回用户不存在
result = ErrorResult.failure(ResultCodeEnum.USER_ACCOUNT_NOT_EXIST,request,HttpStatus.OK);
}
}
response.setContentType("text/json;charset=utf-8");
response.getWriter().write(JSONObject.toJSONString(result));
}
2.2、方式二
第二种,其实我们也可以写一个全局异常拦截器,捕获InternalAuthenticationServiceException 异常来处理它,但是不建议这么做,所以我不细写了,哈哈哈。
@ExceptionHandler(InternalAuthenticationServiceException.class)
@ResponseBody
public ErrorResult handleBusinessException(BusinessException e, HttpServletRequest request){
//一些列操作....
}
InternalAuthenticationServiceException 是用户不存在异常,请正确使用!