作者:手机用户2602884633 | 来源:互联网 | 2023-09-24 18:38
shrio验证cookie有效性概述shrio中提供cookie管理的功能,当用户选择了rememberMe,则下次不需要再登录,而是直接通过本地记录的cookie进行验证,然后就可以
shrio验证COOKIE有效性
概述
shrio中提供COOKIE管理的功能,当用户选择了rememberMe,则下次不需要再登录,而是直接通过本地记录的COOKIE进行验证,然后就可以访问权限为user的页面。
问题
shiro提供清除用户权限的功能,但是那是在代码中动态控制的,你修改了某个用户的权限,可以调用clearCachedAuthorizationInfo(principals)
清除权限信息。但是如果是直接改了数据库里的信息(虽然按道理不应该出这种套路),那么它取COOKIE的时候就不会再验证,不验证用户名密码是否正确,不验证用户里的信息是否有变化。
流程
shiro中解析客户端发来的COOKIE其实主要就是调用AbstractRememberMeManager中的getRememberedPrincipals():
public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {
PrincipalCollection principals = null;
try {
byte[] re = this.getRememberedSerializedIdentity(subjectContext);
if(re != null && re.length > 0) {
principals = this.convertBytesToPrincipals(re, subjectContext);
}
} catch (RuntimeException var4) {
principals = this.onRememberedPrincipalFailure(var4, subjectContext);
}
return principals;
}
在COOKIERememberMeManager中实现了抽象方法getRememberedSerializedIdentity():
protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {
if(!WebUtils.isHttp(subjectContext)) {
if(log.isDebugEnabled()) {
String wsc1 = "SubjectContext argument is not an HTTP-aware instance. This is required to obtain a servlet request and response in order to retrieve the rememberMe COOKIE. Returning immediately and ignoring rememberMe operation.";
log.debug(wsc1);
}
return null;
} else {
WebSubjectContext wsc = (WebSubjectContext)subjectContext;
if(this.isIdentityRemoved(wsc)) {
return null;
} else {
HttpServletRequest request = WebUtils.getHttpRequest(wsc);
HttpServletResponse respOnse= WebUtils.getHttpResponse(wsc);
String base64 = this.getCOOKIE().readValue(request, response);
if("deleteMe".equals(base64)) {
return null;
} else if(base64 != null) {
base64 = this.ensurePadding(base64);
if(log.isTraceEnabled()) {
log.trace("Acquired Base64 encoded identity [" + base64 + "]");
}
byte[] decoded = Base64.decode(base64);
if(log.isTraceEnabled()) {
log.trace("Base64 decoded byte array length: " + (decoded != null?decoded.length:0) + " bytes.");
}
return decoded;
} else {
return null;
}
}
}
}
主要就是进行解密,然后再返回去convertBytesToPrincipals()。
解决方案
熟悉了大致的流程,应该可以想到一个解决方案。就是继承CookirRememberMeManager,重写getRememberedPrincipals():
public class MyRememberMeManager extends COOKIERememberMeManager {
@Autowired
LoginService loginService;
@Override
public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {
PrincipalCollection principals = super.getRememberedPrincipals(subjectContext);
if(null == principals)
return null;
User loginUser = (User) principals.getPrimaryPrincipal();
User checkUser = loginService.check(loginUser.getUsername(), loginUser.getPassword());
if(null == checkUser)
return null;
loginUser.setLevel(checkUser.getLevel());
loginUser.setCounty(checkUser.getCounty());
loginUser.setCity(checkUser.getCity());
loginUser.setTown(checkUser.getTown());
loginUser.setVillage(checkUser.getVillage());
loginUser.setDescription(checkUser.getDescription());
return principals;
}
}