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的合法性。
因本人水平有限,若文章内容存在问题,恳请指出。允许转载,转载请在正文明显处注明原站地址以及原文地址,谢谢!