在 ShiroDatabaseRealm 中对登录结果进行异常捕获
shiro的登录判断是在 ShiroDatabaseRealm 中通过 doGetAuthenticationInfo() 实现的
ShiroDatabaseRealm 是用户自定义的 AuthorizingRealm 子类,用于处理具体的登录逻辑
在 ShiroDatabaseRealm 中做异常捕获的原因是方便后续拦截器直接获取登录失败的原因
public class ShiroDatabaseRealm extends AuthorizingRealm {
private UniversityMemberServiceImpl universityMemberService;public void setUniversityMemberService(UniversityMemberServiceImpl universityMemberService) { this.universityMemberService = universityMemberService; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws
AuthenticationException {
UsernamePasswordCheckCodeToken token = (UsernamePasswordCheckCodeToken) authcToken;
token.setRememberMe(false);UniversityMemberDTO member = universityMemberService.getUniversityMember(token.getUsername()); // 未获取到用户信息可能是因为用户未激活 if (member == null) { throw new UnknownAccountException("用户不存在"); } // 未激活禁止登录 if (MemberStatus.initStatus.equals(member.getStatus())) { // 自定义异常,实现自AccountException throw new InactivateAccountException("账号未激活,请激活或联系管理员"); } // 被禁用禁止登录 if (MemberStatus.disableStatus.equals(member.getStatus())) { throw new DisabledAccountException("账号被禁用,请联系管理员"); } byte[] salt = EncodeUtils.hexDecode(member.getSalt()); return new SimpleAuthenticationInfo(member, member.getLoginPassword(), ByteSource.Util.bytes(salt), getName()); } }
重写 LoginFormAuthenticationFilter
当登录成功或失败后会通过默认拦截器 FormAuthenticationFilter 对结果进行拦截
此处的 LoginFormAuthenticationFilter 就是继承自 FormAuthenticationFilter ,作为自定义的登录拦截器
需要在 applicationContext-shiro.xml 中引用
isAjax() 函数用于判断当前请求是否是异步的,避免错误拦截了所有请求
因为登录失败的原因在 ShiroDatabaseRealm 中已经指定了,所以大部分原因可以通过 e.getMessage() 获取
但是密码是否错误的逻辑判断是在 ShiroDatabaseRealm 内部判断的,如果错误会返回 IncorrectCredentialsException 异常
此处只需要单独判断异常类型并自定义错误信息即可
onLoginSuccess() 是登录成功后的拦截
如果不把登录成功后的拦截也修改成异步的,登录成功将会把整个成功后的页面返回到异步登录请求的回调中
onLoginFailure() 是登录失败后的拦截
public class LoginFormAuthenticationFilter extends
FormAuthenticationFilter {
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response)
throws Exception {
if (!isAjax(request)) {
issueSuccessRedirect(request, response);
} else {
sendResult(response, true, “”);
}return false; } @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse
response) {
// 只拦截ajax请求
if (!isAjax(request)) {
setFailureAttribute(request, e);
}String message = ""; if (e instanceof IncorrectCredentialsException) { message = "密码错误"; } else { message = e.getMessage(); } // 发送结果到前端 sendResult(response, false, message); return false; } /** * 异步判断 */ private Boolean isAjax(ServletRequest request) { return ("XMLHttpRequest").equalsIgnoreCase(((HttpServletRequest)
request).getHeader(“X-Requested-With”));
}/** * 发送结果到前端 */ private void sendResult(ServletResponse response, Boolean result, String message) { try { response.setCharacterEncoding("UTF-8"); PrintWriter writer = response.getWriter(); StringBuffer buffer = new StringBuffer(); buffer.append("{"); buffer.append("\"success\": ").append(result).append(","); buffer.append("\"message\": \"").append(message).append("\""); buffer.append("}"); writer.println(buffer.toString()); writer.flush(); writer.close(); } catch (Exception e) { e.printStackTrace(); } } }