shiro權限框架,用戶登錄方法的subject.login(token)會進入自定義的UserNamePasswordRealm類的doGetAuthenticationInfo身份驗證方法
通常情況,doGetAuthenticationInfo寫法如下:
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
User loginUser = userService.getUserByName(token.getUsername());
if (ObjectUtils.isEmpty(loginUser)) {
throw new UnknownAccountException();
}
if(!loginUser.getPassWord().equals(MD5Util.md5s(String.valueOf(token.getPassword())))){
throw new IncorrectCredentialsException();
}
//其他各種驗證
。。。
}
login登錄方法:
@ResponseBody
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String doUserLogin(User user, HttpServletRequest request, Model model) {
...
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassWord());
try {
subject.login(token);
} catch (UnknownAccountException uae) {
} catch (IncorrectCredentialsException ice) {
} catch (LockedAccountException lae) {
} catch (ExcessiveAttemptsException eae) {
} catch (AuthenticationException ae) {
}
...
}
可是最近一次項目,發現通用的方法行不通了,doGetAuthenticationInfo方法拋出的各種異常如UnknownAccountException(包括自定義的異常),外部都無法准確捕捉。
外部login捕捉的異常統一被改寫為 AuthenticationException異常(IncorrectCredentialsException等異常的父類),且異常的msg內容也被改寫。內容如下:
原因在subject.login(token)的源碼里,源碼有這么一段:
我們進入doSingleRealmAuthentication方法,可以看見方法里面外拋了UnknownAccountException等異常。
所以如果項目中只定義了一個realm,比如用來進行登錄的身份驗證,外部是可以正常捕捉的。
但是此次項目我定義了兩個realm,一個用來進行登錄的身份驗證,另一個用來登錄后,驗證各種請求攜帶的的token。
我們進入doMultiRealmAuthentication方法,內容如下
再進入afterAllAttempts的實現類,如圖5。
發現拋出的異常都被統一改為AuthenticationException異常,且msg也被改寫,正如圖1所示。
結論
外部無法捕捉doGetAuthenticationInfo方法拋出的異常,原因在於源碼,而不是自己的代碼有問題。
如果沒有改寫源碼的本事,那么外部想要捕捉各種異常,並在前端顯示各種提示語,怎么辦?
我的臨時解決方法是,doGetAuthenticationInfo只用來驗證用戶名和密碼,
外部直接捕捉AuthenticationException異常,其他的各種驗證從doGetAuthenticationInfo方法移至login。