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,目前这个问题还没有想到比较好的解决方案。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。