首页 > 开发 > Java > 正文

spring boot整合redis实现shiro的分布式session共享的方法

2024-07-13 10:17:22
字体:
来源:转载
供稿:网友

我们知道,shiro是通过SessionManager来管理Session的,而对于Session的操作则是通过SessionDao来实现的,默认的情况下,shiro实现了两种SessionDao,分别为CachingSessionDAO和MemorySessionDAO,当我们使用EhCache缓存时,则是使用的CachingSessionDAO,不适用缓存的情况下,就会选择基于内存的SessionDao.所以,如果我们想实现基于Redis的分布式Session共享,重点在于重写SessionManager中的SessionDao。我们的重写代码如下:

package com.chhliu.springboot.shiro.cache; import java.io.Serializable; import java.util.Collection; import java.util.concurrent.TimeUnit; import org.apache.shiro.session.Session; import org.apache.shiro.session.UnknownSessionException; import org.apache.shiro.session.mgt.eis.AbstractSessionDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service;  @Service @SuppressWarnings({ "rawtypes", "unchecked" }) public class RedisSessionDao extends AbstractSessionDAO {    // Session超时时间,单位为毫秒   private long expireTime = 120000;    @Autowired   private RedisTemplate redisTemplate;// Redis操作类,对这个使用不熟悉的,可以参考前面的博客    public RedisSessionDao() {     super();   }    public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) {     super();     this.expireTime = expireTime;     this.redisTemplate = redisTemplate;   }    @Override // 更新session   public void update(Session session) throws UnknownSessionException {     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   public void delete(Session session) {     System.out.println("===============delete================");     if (null == session) {       return;     }     redisTemplate.opsForValue().getOperations().delete(session.getId());   }    @Override// 获取活跃的session,可以用来统计在线人数,如果要实现这个功能,可以在将session加入redis时指定一个session前缀,统计的时候则使用keys("session-prefix*")的方式来模糊查找redis中所有的session集合   public Collection<Session> getActiveSessions() {     System.out.println("==============getActiveSessions=================");     return redisTemplate.keys("*");   }    @Override// 加入session   protected Serializable doCreate(Session session) {     System.out.println("===============doCreate================");     Serializable sessionId = this.generateSessionId(session);     this.assignSessionId(session, sessionId);      redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);     return sessionId;   }    @Override// 读取session   protected Session doReadSession(Serializable sessionId) {     System.out.println("==============doReadSession=================");     if (sessionId == null) {       return null;     }     return (Session) redisTemplate.opsForValue().get(sessionId);   }    public long getExpireTime() {     return expireTime;   }    public void setExpireTime(long expireTime) {     this.expireTime = expireTime;   }    public RedisTemplate getRedisTemplate() {     return redisTemplate;   }    public void setRedisTemplate(RedisTemplate redisTemplate) {     this.redisTemplate = redisTemplate;   } } 

SessionDao实现完了之后,我们就需要将SessionDao加入SessionManager中了,代码如下:

 @Bean   public DefaultWebSessionManager configWebSessionManager(){     DefaultWebSessionManager manager = new DefaultWebSessionManager();     manager.setCacheManager(cacheManager);// 加入缓存管理器     manager.setSessionDAO(sessionDao);// 设置SessionDao     manager.setDeleteInvalidSessions(true);// 删除过期的session     manager.setGlobalSessionTimeout(sessionDao.getExpireTime());// 设置全局session超时时间     manager.setSessionValidationSchedulerEnabled(true);// 是否定时检查session          return manager;   } 

最后一步就是将SessionManager配置到SecurityManager中了

@Bean   public SecurityManager securityManager(DefaultWebSessionManager webSessionManager) {     DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();     // 设置realm.     securityManager.setRealm(myShiroRealm());      // 注入缓存管理器;     securityManager.setCacheManager(cacheManager);// 这个如果执行多次,也是同样的一个对象;          // session管理器     securityManager.setSessionManager(webSessionManager);          //注入记住我管理器;     securityManager.setRememberMeManager(rememberMeManager());     return securityManager;   } 

测试结果如下:

==============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,目前这个问题还没有想到比较好的解决方案。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VeVb武林网。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表