spring boot整合redis实现shiro的分布式session共享的方法
我们知道,shiro是通过SessionManager来管理Session的,而对于Session的操作则是通过SessionDao来实现的,默认的情况下,shiro实现了两种SessionDao,分别为CachingSessionDAO和MemorySessionDAO,当我们使用EhCache缓存时,则是使用的CachingSessionDAO,不适用缓存的情况下,就会选择基于内存的SessionDao.所以,如果我们想实现基于Redis的分布式Session共享,重点在于重写SessionManager中的SessionDao。我们的重写代码如下:
packagecom.chhliu.springboot.shiro.cache;
importjava.io.Serializable;
importjava.util.Collection;
importjava.util.concurrent.TimeUnit;
importorg.apache.shiro.session.Session;
importorg.apache.shiro.session.UnknownSessionException;
importorg.apache.shiro.session.mgt.eis.AbstractSessionDAO;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.stereotype.Service;
@Service
@SuppressWarnings({"rawtypes","unchecked"})
publicclassRedisSessionDaoextendsAbstractSessionDAO{
//Session超时时间,单位为毫秒
privatelongexpireTime=120000;
@Autowired
privateRedisTemplateredisTemplate;//Redis操作类,对这个使用不熟悉的,可以参考前面的博客
publicRedisSessionDao(){
super();
}
publicRedisSessionDao(longexpireTime,RedisTemplateredisTemplate){
super();
this.expireTime=expireTime;
this.redisTemplate=redisTemplate;
}
@Override//更新session
publicvoidupdate(Sessionsession)throwsUnknownSessionException{
System.out.println("===============update================");
if(session==null||session.getId()==null){
return;
}
session.setTimeout(expireTime);
redisTemplate.opsForValue().set(session.getId(),session,expireTime,TimeUnit.MILLISECONDS);
}
@Override//删除session
publicvoiddelete(Sessionsession){
System.out.println("===============delete================");
if(null==session){
return;
}
redisTemplate.opsForValue().getOperations().delete(session.getId());
}
@Override//获取活跃的session,可以用来统计在线人数,如果要实现这个功能,可以在将session加入redis时指定一个session前缀,统计的时候则使用keys("session-prefix*")的方式来模糊查找redis中所有的session集合
publicCollectiongetActiveSessions(){
System.out.println("==============getActiveSessions=================");
returnredisTemplate.keys("*");
}
@Override//加入session
protectedSerializabledoCreate(Sessionsession){
System.out.println("===============doCreate================");
SerializablesessionId=this.generateSessionId(session);
this.assignSessionId(session,sessionId);
redisTemplate.opsForValue().set(session.getId(),session,expireTime,TimeUnit.MILLISECONDS);
returnsessionId;
}
@Override//读取session
protectedSessiondoReadSession(SerializablesessionId){
System.out.println("==============doReadSession=================");
if(sessionId==null){
returnnull;
}
return(Session)redisTemplate.opsForValue().get(sessionId);
}
publiclonggetExpireTime(){
returnexpireTime;
}
publicvoidsetExpireTime(longexpireTime){
this.expireTime=expireTime;
}
publicRedisTemplategetRedisTemplate(){
returnredisTemplate;
}
publicvoidsetRedisTemplate(RedisTemplateredisTemplate){
this.redisTemplate=redisTemplate;
}
}
SessionDao实现完了之后,我们就需要将SessionDao加入SessionManager中了,代码如下:
@Bean
publicDefaultWebSessionManagerconfigWebSessionManager(){
DefaultWebSessionManagermanager=newDefaultWebSessionManager();
manager.setCacheManager(cacheManager);//加入缓存管理器
manager.setSessionDAO(sessionDao);//设置SessionDao
manager.setDeleteInvalidSessions(true);//删除过期的session
manager.setGlobalSessionTimeout(sessionDao.getExpireTime());//设置全局session超时时间
manager.setSessionValidationSchedulerEnabled(true);//是否定时检查session
returnmanager;
}
最后一步就是将SessionManager配置到SecurityManager中了
@Bean
publicSecurityManagersecurityManager(DefaultWebSessionManagerwebSessionManager){
DefaultWebSecurityManagersecurityManager=newDefaultWebSecurityManager();
//设置realm.
securityManager.setRealm(myShiroRealm());
//注入缓存管理器;
securityManager.setCacheManager(cacheManager);//这个如果执行多次,也是同样的一个对象;
//session管理器
securityManager.setSessionManager(webSessionManager);
//注入记住我管理器;
securityManager.setRememberMeManager(rememberMeManager());
returnsecurityManager;
}
测试结果如下:
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
===============update================
==============doReadSession=================
==============doReadSession=================
===============update================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
权限配置-->MyShiroRealm.doGetAuthorizationInfo()
==============doReadSession=================
我们会发现,当一个页面中存在多个资源的时候,会不停的调用doReadSession,update方法来读取和更新session,目前这个问题还没有想到比较好的解决方案。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。