Spring Shiro 使用默认的Session会话管理

项目中用到了shiro session会话管理机制,今天来总结一下,以下都是在spring boot框架实现。

shiro的session管理机制很完善,也是独立于j2ee容器且不依赖的,所以我们完全可以使用shiro提供给我们的session会话管理来实现我们的业务逻辑,默认提供的sessionDAO是memorySessionDAO,这里也主要讲它的配置和原理。

首先来看下如何在spring boot下配置默认的session会话管理:

ShiroConfig类:

1@Configuration 2public class ShiroConfig { 3 @Value("${spring.redis.host}") 4 private String host; 5 @Value("${spring.redis.password}") 6 private String password; 7 @Value("${spring.redis.port}") 8 private int port; 9 @Value("${spring.redis.timeout}") 10 private int timeout; 11 12 @Value("${spring.cache.type}") 13 private String cacheType ; 14 15 @Value("${server.session-timeout}") 16 private int tomcatTimeout; 17 18 @Bean 19 public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { 20 return new LifecycleBeanPostProcessor(); 21 } 22 23 24 @Bean 25 public SecurityManager securityManager() { 26 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 27 //设置realm. 28 securityManager.setRealm(userRealm()); 29 // 自定义缓存实现 使用redis 30 if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) { 31 securityManager.setCacheManager(rediscacheManager()); 32 } else { 33 securityManager.setCacheManager(ehCacheManager()); 34 } 35 securityManager.setSessionManager(sessionManager()); 36 return securityManager; 37 } 38 39 @Bean 40 UserRealm userRealm() { 41 UserRealm userRealm = new UserRealm(); 42 return userRealm; 43 } 44 45 46 @Bean 47 public SessionDAO sessionDAO() { 48 return new MemorySessionDAO();//使用默认的MemorySessionDAO 49 } 50 51 /** 52 * shiro session的管理 53 */ 54 @Bean 55 public DefaultWebSessionManager sessionManager() { //配置默认的sesssion管理器 56 DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); 57 sessionManager.setGlobalSessionTimeout(tomcatTimeout * 1000); 58 sessionManager.setSessionDAO(sessionDAO()); 59 Collection<SessionListener> listeners = new ArrayList<SessionListener>(); 60 listeners.add(new BDSessionListener()); 61 sessionManager.setSessionListeners(listeners); 62 return sessionManager; 63 } 64 65 @Bean 66 public EhCacheManager ehCacheManager() { 67 EhCacheManager em = new EhCacheManager(); 68 em.setCacheManager(cacheManager()); 69 return em; 70 } 71 72 @Bean("cacheManager2") 73 CacheManager cacheManager(){ 74 return CacheManager.create(); 75 } 76 77 78}

DefaultWebSessionManager是我们配置管理器的核心类,里面配置了session的超时时间,sessionDAO和监听器。

在上面我们向spring boot注入了:

1 @Bean 2 public SessionDAO sessionDAO() { 3 return new MemorySessionDAO();//使用默认的MemorySessionDAO 4 }

  MemorySessionDAO是shiro已经实现的Session的CRUD实现类,包括对session的操作,增删改读。

  下面来看下MemorySessionDAO的源码实现:

1public class MemorySessionDAO extends AbstractSessionDAO { 2 private static final Logger log = LoggerFactory.getLogger(MemorySessionDAO.class); 3 private ConcurrentMap<Serializable, Session> sessions = new ConcurrentHashMap(); 4 5 public MemorySessionDAO() { 6 } 7 8 protected Serializable doCreate(Session session) { 9 Serializable sessionId = this.generateSessionId(session); 10 this.assignSessionId(session, sessionId); 11 this.storeSession(sessionId, session); 12 return sessionId; 13 } 14 15 protected Session storeSession(Serializable id, Session session) { 16 if (id == null) { 17 throw new NullPointerException("id argument cannot be null."); 18 } else { 19 return (Session)this.sessions.putIfAbsent(id, session); 20 } 21 } 22 23 protected Session doReadSession(Serializable sessionId) { 24 return (Session)this.sessions.get(sessionId); 25 } 26 27 public void update(Session session) throws UnknownSessionException { 28 this.storeSession(session.getId(), session); 29 } 30 31 public void delete(Session session) { 32 if (session == null) { 33 throw new NullPointerException("session argument cannot be null."); 34 } else { 35 Serializable id = session.getId(); 36 if (id != null) { 37 this.sessions.remove(id); 38 } 39 40 } 41 } 42 43 public Collection<Session> getActiveSessions() { 44 Collection<Session> values = this.sessions.values(); 45 return (Collection)(CollectionUtils.isEmpty(values) ? Collections.emptySet() : Collections.unmodifiableCollection(values)); 46 } 47}

 在源码中我们能看到MemorySessionDAO继承了AbstractSessionDAO类,这是一个抽象类,里面实现了一部分方法,而AbstractSessionDAO又实现了SessionDAO接口,这才是顶级接口,里面提供了5个方法:

1public interface SessionDAO { 2 Serializable create(Session var1); 3 4 Session readSession(Serializable var1) throws UnknownSessionException; 5 6 void update(Session var1) throws UnknownSessionException; 7 8 void delete(Session var1); 9 10 Collection<Session> getActiveSessions(); 11}

 这5个方法也是memorySessionDAO实现的5个方法。 

 可以看出配置非常简单,我们几乎不需要做任何事情,下面来看看怎么来使用吧,

 以一个SessionService为例:

1@Service 2public interface SessionService { 3 List<UserOnline> list(); //得到系统在线用户 4 5 boolean forceLogout(String sessionId); //强制登出 6}

里面有两个方法,分别是查询系统当前在线的用户,以及强制登出某个用户。

实现如下:

1@Service 2public class SessionServiceImpl implements SessionService { 3 private final SessionDAO sessionDAO; 4 5 @Autowired 6 public SessionServiceImpl(SessionDAO sessionDAO) { 7 this.sessionDAO = sessionDAO; 8 } 9 10 @Override 11 public List<UserOnline> list() { 12 List<UserOnline> list = new ArrayList<>(); 13 Collection<Session> sessions = sessionDAO.getActiveSessions(); 14 for (Session session : sessions) { 15 UserOnline userOnline = new UserOnline(); 16 if (session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) == null) { 17 continue; 18 } else { 19 SimplePrincipalCollection principalCollection = (SimplePrincipalCollection) session 20 .getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); 21 UserDO userDO = (UserDO) principalCollection.getPrimaryPrincipal(); 22 userOnline.setUsername(userDO.getUsername()); 23 } 24 userOnline.setId((String) session.getId()); 25 userOnline.setHost(session.getHost()); 26 userOnline.setStartTimestamp(session.getStartTimestamp()); 27 userOnline.setLastAccessTime(session.getLastAccessTime()); 28 userOnline.setTimeout(session.getTimeout()); 29 list.add(userOnline); 30 } 31 return list; 32 } 33 34 35 @Override 36 public boolean forceLogout(String sessionId) { 37 Session session = sessionDAO.readSession(sessionId); 38 session.setTimeout(0); 39 return true; 40 } 41}

在代码中,我们注入了shiro的SessionDAO,

 Collection<Session> sessions = sessionDAO.getActiveSessions();  可以得到当前在线的session集合。

 每一个session都封装了用户的各种信息,

 userOnline.setId((String) session.getId()); //得到session的ID
 userOnline.setHost(session.getHost()); //得到用户的主机
 userOnline.setStartTimestamp(session.getStartTimestamp()); //得到用户的登录时间
 userOnline.setLastAccessTime(session.getLastAccessTime());//得到用户最后登录时间
 userOnline.setTimeout(session.getTimeout());/得到过期时间

 如果我们想在强制让某用户登出系统,只需要session.setTimeout(0)即可。

 是不是觉得非常简便,如果系统需求不高,我们完全可以使用shiro为我们实现的这个sessionDAO,

而如果系统有定制需求,我们也可以实现自定义的sessionDAO,比如我们可以将session的CRUD通过redis来实现,同样的继承AbstractSessionDAO类,重写它的方法即可,将session的各种存取修改以redis为载体,基本的逻辑就是这样,如果有问题欢迎在评论中留言。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Spring Shiro 使用默认的Session会话管理 - HelloWorld