我们知道,shiro是通过SessionManager来管理Session的,而对于Session的操作则是通过SessionDao来实现的,默认的情况下,shiro实现了两种SessionDao,分别为CachingSessionDAO和MemorySessionDAO,当我们使用EhCache缓存时,则是使用的CachingSessionDAO,不适用缓存的情况下,就会选择基于内存的SessionDao.所以,如果我们想实现基于Redis的分布式Session共享,重点在于重写SessionManager中的SessionDao。我们的重写代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
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中了,代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
@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中了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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,目前这个问题还没有想到比较好的解决方案。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/liuchuanhong1/article/details/76690682