shiro的介绍在这里就不说了,主要讲下shiro的rememberMe cookie。在shiro中有一个类实现了rememberMe功能, org.apache.shiro.web.mgt.CookieRememberMeManager
。在登录时,代码也很简单:
UsernamePasswordToken token = new UsernamePasswordToken(username,password); token.setRememberMe(true); subject.login(token);
这之后的大致流程如下:
org.apache.shiro.web.mgt.CookieRememberMeManager
),委托rememberMe的工作。
org.apache.shiro.web.mgt.CookieRememberMeManager
继承 AbstractRememberMeManager
,当登录成功后调用以下方法:
publicvoidonSuccessfulLogin(Subject subject, AuthenticationToken token, AuthenticationInfo info){ this.forgetIdentity(subject); if(this.isRememberMe(token)) { this.rememberIdentity(subject, token, info); } else if(log.isDebugEnabled()) { log.debug("AuthenticationToken did not indicate RememberMe is requested. RememberMe functionality will not be executed for corresponding account."); } }
以上代码主要做了2件事:
设置rememberMe cookie的代码如下:
protectedvoidrememberSerializedIdentity(Subject subject,byte[] serialized){ if(!WebUtils.isHttp(subject)) { if(log.isDebugEnabled()) { String request1 = "Subject argument is not an HTTP-aware instance. This is required to obtain a servlet request and response in order to set the rememberMe cookie. Returning immediately and ignoring rememberMe operation."; log.debug(request1); } } else { HttpServletRequest request = WebUtils.getHttpRequest(subject); HttpServletResponse response = WebUtils.getHttpResponse(subject); String base64 = Base64.encodeToString(serialized); Cookie template = this.getCookie(); SimpleCookie cookie = new SimpleCookie(template); cookie.setValue(base64); cookie.saveTo(request, response); } }
其中 cookie.saveTo(request, response);
便是将base64编码后的值写到浏览器。
那么这个rememberMe cookie,也就是上面函数中的第二个参数 serialized
是如何生成的?
在上面的 onSuccessfulLogin
中, this.rememberIdentity(subject, token, info);
主要调用链如下:
publicvoidrememberIdentity(Subject subject, AuthenticationToken token, AuthenticationInfo authcInfo){ PrincipalCollection principals = this.getIdentityToRemember(subject, authcInfo); this.rememberIdentity(subject, principals); }
protectedvoidrememberIdentity(Subject subject, PrincipalCollection accountPrincipals){ byte[] bytes = this.convertPrincipalsToBytes(accountPrincipals); this.rememberSerializedIdentity(subject, bytes); }
protected byte[] convertPrincipalsToBytes(PrincipalCollection principals) { //序列化principals对象,得到的值再经过aes加密和base64编码 byte[] bytes = this.serialize(principals); if(this.getCipherService() != null) { bytes = this.encrypt(bytes); } return bytes; }
protected byte[] encrypt(byte[] serialized) { byte[] value = serialized; CipherService cipherService = this.getCipherService(); if(cipherService != null) { ByteSource byteSource = cipherService.encrypt(serialized, this.getEncryptionCipherKey()); value = byteSource.getBytes(); } return value; }
所以得到rememberMe cookie过程如下:
当客户端带着这个rememberMe cookie访问时,将会按照下面的过程来寻找已记住的身份信息:
之前一直疑惑shiro是如何储存这个rememberMe cookie的,难道是持久化了?否则服务器重启后为什么这个cookie依旧有效。现在大致上就明白了,只有反序列化成功了,才能证明此rememberMe cookie的合法性。
因本人水平有限,若文章内容存在问题,恳请指出。允许转载,转载请在正文明显处注明原站地址以及原文地址,谢谢!