shiro框架 redis集群管理session

最近用shiro,遇到很多坑,边学边用,现在记下来。文采不够,直接上代码

1.坐标

 1               <dependency>
 2             <groupId>org.apache.shiro</groupId>
 3             <artifactId>shiro-web</artifactId>
 4             <version>${shiro.version}</version>
 5         </dependency>
 6         <dependency>
 7             <groupId>org.apache.shiro</groupId>
 8             <artifactId>shiro-core</artifactId>
 9             <version>${shiro.version}</version>
10         </dependency>
11         <dependency>
12             <groupId>org.apache.shiro</groupId>
13             <artifactId>shiro-spring</artifactId>
14             <version>${shiro.version}</version>
15         </dependency>
16         <dependency>
17             <groupId>org.apache.shiro</groupId>
18             <artifactId>shiro-ehcache</artifactId>
19             <version>${shiro.version}</version>
20         </dependency>
21         <!-- ehcache -->
22         <dependency>
23             <groupId>net.sf.ehcache</groupId>
24             <artifactId>ehcache-core</artifactId>
25             <version>2.6.6</version>
26         </dependency>            
View Code

  jar包版本 <shiro.version>1.4.0</shiro.version>

2.web.xml

<filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
View Code

  这里要注意的是filter-name 必须更filter bean的名字一样

3.applicationcontext-shiro.xml

 1 <!-- 自定义realm -->
 2     <bean id="comprehensiveRealm" class="com.comprehensive.shiro.ComprehensiveRealm">
 3         <property name="authorizationCacheName" value="comprehensive"></property>
 4         <property name="authenticationCachingEnabled" value="true" />
 5         <property name="cachingEnabled" value="true" />
 6     </bean>
 7 
 8     <!-- 安全管理器 -->
 9     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
10         <property name="cacheManager" ref="redisCacheManager" />
11         <property name="realm" ref="comprehensiveRealm" />
12         <!-- <property name="sessionMode" value="http" /> -->
13         <property name="sessionManager" ref="defaultWebSessionManager" />
14     </bean>
15 
16 
17     <!-- 初始化ehCacheManager缓存,用于缓存权限 -->
18     <bean id="ehCacheManagerFactoryBean" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
19         <property name="configLocation" value="classpath:/spring/ehcache.xml" />
20     </bean>
21     <bean id="ehCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
22         <property name="cacheManager" ref="ehCacheManagerFactoryBean"></property>
23     </bean>
24     
25     <!-- 自定义redis缓存,用于缓存权限 -->
26     <bean id="redisCacheManager" class="com.comprehensive.shiro.cache.RedisCacheManager">
27         <property name="compCacheManager" ref="compRedisCacheManager"></property>
28     </bean>
29 
30     <!-- 自定义redisSessionDao -->
31     <bean id="redisSessionDao" class="com.comprehensive.shiro.session.RedisSessionDao">
32         <property name="compCacheManager" ref="compRedisCacheManager" />
33     </bean>
34 
35     <!-- session管理器 -->
36     <bean id="defaultWebSessionManager"    class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
37         <property name="sessionDAO" ref="redisSessionDao" />
38         <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
39         <property name="sessionIdCookie" ref="sessionIdCookie" />
40         <!-- 设置全局会话超时时间,默认30分钟(1800000) -->
41         <property name="globalSessionTimeout" value="1800000" />
42         <!-- 是否在会话过期后会调用SessionDAO的delete方法删除会话 默认true -->
43         <property name="deleteInvalidSessions" value="true" />
44         <!-- 会话验证器调度时间 -->
45         <property name="sessionValidationInterval" value="1800000" />
46         <!-- 定时检查失效的session -->
47         <property name="sessionValidationSchedulerEnabled" value="true" />
48     </bean>
49 
50     <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
51         <!-- cookie的name,对应的默认是 JSESSIONID -->
52         <constructor-arg name="name" value="comprehensive.session.id" />
53         <!-- jsessionId的path为 / 用于多个系统共享jsessionId -->
54         <property name="path" value="/" />
55         <property name="httpOnly" value="true" />
56     </bean>
57 
58     <!-- 管理shiro bean的生命周期 -->
59     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
60 
61     <!-- shiro bean -->
62     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
63         <property name="securityManager" ref="securityManager" />
64         <property name="loginUrl" value="/system/login" />
65         <!-- <property name="successUrl" value="/aa" /> -->
66         <property name="unauthorizedUrl" value="/system/unauthorized" />
67         <property name="filters">
68             <util:map>
69                 <entry key="logout" value-ref="logoutFilter"></entry>
70             </util:map>
71         </property>
72         <property name="filterChainDefinitions">
73             <value>
74                 /js/** = anon
75                 /css/** = anon
76                 /images/** = anon
77                 /system/list* = roles[admin]
78                 /system/aa = perms[admin1qqq]
79                 /system/logout = logout
80                 /system/** = authc
81             </value>
82         </property>
83     </bean>
84     
85     <!-- logout过滤器  -->
86     <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
87         <property name="redirectUrl" value="/system/login"></property>
88     </bean>
View Code

  这里面要注意的是:cacheManager我配置了两个,一个是ehCacheManager实现,一个是redisCacheManager实现,用的时候配置一个就可以了。

4.shiro中SessionDAO这个类可以管理session的创建,获取,删除,实际用的时候可以继承AbstractSessionDAO。

 1 public class RedisSessionDao extends AbstractSessionDAO {
 2     private Logger logger = LoggerFactory.getLogger(LoggerEnum.OPERATION_LOG.toString());
 3 
 4     private final String REDIS_SHIRO_SESSION = "comprehensive-shiro-session:";
 5 
 6     private int expire = 60 * 30;
 7 
 8     private CompCacheManager compCacheManager;
 9 
10     public CompCacheManager getCompCacheManager() {
11         return compCacheManager;
12     }
13 
14     public void setCompCacheManager(CompCacheManager compCacheManager) {
15         this.compCacheManager = compCacheManager;
16     }
17 
18     public void setExpire(int expire) {
19         this.expire = expire;
20     }
21 
22     @Override
23     public void update(Session session) throws UnknownSessionException {
24         if (session == null) {
25             logger.error("shiro update session: {session is null}  ");
26             return;
27         }
28         logger.debug("shiro update session: {sessionid}  " + session.getId());
29         this.saveSession(session);
30     }
31 
32     @Override
33     public void delete(Session session) {
34         if (session == null || session.getId() == null) {
35             logger.error("session or session id is null");
36             return;
37         }
38         logger.debug("shiro delete session: {sessionid}  " + session.getId());
39         compCacheManager.delObj(getKey(session.getId()));
40     }
41 
42     @Override
43     public Collection<Session> getActiveSessions() {
44         logger.debug("shiro getActiveSessions session");
45         Set<Session> sessions = new HashSet<>();
46         Set<byte[]> keys = compCacheManager.keysObj(REDIS_SHIRO_SESSION + "*");
47         if (keys != null && keys.size() > 0) {
48             for (byte[] bs : keys) {
49                 Session session = (Session) SerializaUtil.unserializable(bs);
50                 sessions.add(session);
51             }
52         }
53         return sessions;
54     }
55 
56     @Override
57     protected Serializable doCreate(Session session) {
58         logger.debug("shiro doCreate session");
59         Serializable sessionId = this.generateSessionId(session);
60         this.assignSessionId(session, sessionId);
61         this.saveSession(session);
62         return sessionId;
63     }
64 
65     @Override
66     protected Session doReadSession(Serializable sessionId) {
67         if (sessionId == null) {
68             logger.error("session id is null");
69             return null;
70         }
71         logger.debug("shiro doReadSession session:{sessionId}  " + sessionId);
72         return (Session) compCacheManager.getObj(getKey(sessionId));
73     }
74 
75     private String getKey(Serializable sessionId) {
76         return this.REDIS_SHIRO_SESSION + sessionId;
77     }
78 
79     private void saveSession(Session session) {
80         logger.debug("shiro saveSession session");
81         if (session == null || session.getId() == null) {
82             logger.error("session or session id is null");
83             return;
84         }
85         session.setTimeout(expire * 1000);
86         compCacheManager.setObj(getKey(session.getId()), session, expire);
87     }
88 }
View Code

5.shiro中对权限的缓存,默认是ehcache,要用的话,只需要配置就可以,下面代码,是用redis来缓存权限

  写两个类分别实现shiro的cache接口和继承shiro的CacheManager类

  1 @SuppressWarnings("unchecked")
  2 public class RedisCache<K, V> implements Cache<K, V> {
  3     private Logger logger = LoggerFactory.getLogger(RedisCache.class);
  4 
  5     private final String REDIS_SHIRO_CACHE = "comprehensive-shiro-cache:";
  6 
  7     private int expire = 60 * 30;
  8 
  9     private CompCacheManager compCacheManager;
 10 
 11     private String name;
 12 
 13     public RedisCache(CompCacheManager compCacheManager, String name) {
 14         super();
 15         this.compCacheManager = compCacheManager;
 16         this.name = name;
 17     }
 18 
 19     public String getName() {
 20         if (name == null)
 21             return "";
 22         return name;
 23     }
 24 
 25     public void setName(String name) {
 26         this.name = name;
 27     }
 28 
 29     @Override
 30     public V get(K key) throws CacheException {
 31         try {
 32             if (key == null) {
 33                 return null;
 34             } else {
 35                 byte[] value = compCacheManager.getObj(getByteKey(key));
 36                 return (V) SerializaUtil.unserializable(value);
 37             }
 38         } catch (Throwable t) {
 39             throw new CacheException(t);
 40         }
 41     }
 42 
 43     @Override
 44     public V put(K key, V value) throws CacheException {
 45         try {
 46             V v = get(key);
 47             compCacheManager.setObj(getByteKey(key), SerializaUtil.serializable(value), expire);
 48             return v;
 49         } catch (Throwable t) {
 50             throw new CacheException(t);
 51         }
 52     }
 53 
 54     @Override
 55     public V remove(K key) throws CacheException {
 56         try {
 57             V v = get(key);
 58             compCacheManager.delObj(getByteKey(key));
 59             return v;
 60         } catch (Throwable t) {
 61             throw new CacheException(t);
 62         }
 63     }
 64 
 65     @Override
 66     public void clear() throws CacheException {
 67         try {
 68             String preKey = this.REDIS_SHIRO_CACHE + "*";
 69             compCacheManager.delAll(preKey);
 70         } catch (Throwable t) {
 71             throw new CacheException(t);
 72         }
 73     }
 74 
 75     @Override
 76     public int size() {
 77         if (keys() == null) {
 78             return 0;
 79         }
 80         return keys().size();
 81     }
 82 
 83     @Override
 84     public Set<K> keys() {
 85         try {
 86             Set<byte[]> keys = compCacheManager.keysObj(this.REDIS_SHIRO_CACHE + "*");
 87             if (CollectionUtils.isEmpty(keys)) {
 88                 return Collections.emptySet();
 89             } else {
 90                 Set<K> newKeys = new HashSet<K>(keys.size());
 91                 for (byte[] key : keys) {
 92                     Object o = SerializaUtil.unserializable(key);
 93                     newKeys.add((K) o);
 94                 }
 95                 return newKeys;
 96             }
 97         } catch (Throwable t) {
 98             throw new CacheException(t);
 99         }
100     }
101 
102     @Override
103     public Collection<V> values() {
104         try {
105             Set<byte[]> keys = compCacheManager.keysObj(this.REDIS_SHIRO_CACHE + "*");
106             if (!CollectionUtils.isEmpty(keys)) {
107                 List<V> values = new ArrayList<V>(keys.size());
108                 for (byte[] key : keys) {
109                     V value = get((K) key);
110                     if (value != null) {
111                         values.add(value);
112                     }
113                 }
114                 return Collections.unmodifiableList(values);
115             } else {
116                 return Collections.emptyList();
117             }
118         } catch (Throwable t) {
119             throw new CacheException(t);
120         }
121     }
122 
123     private byte[] getByteKey(K key) {
124         if (key instanceof String) {
125             String preKey = this.REDIS_SHIRO_CACHE + getName() + ":" + key;
126             return preKey.getBytes();
127         } else {
128             return SerializaUtil.serializable(key);
129         }
130     }
131 
132 }
View Code
 1 @SuppressWarnings("rawtypes")
 2 public class RedisCacheManager implements CacheManager {
 3     private CompCacheManager compCacheManager;
 4 
 5     public void setCompCacheManager(CompCacheManager compCacheManager) {
 6         this.compCacheManager = compCacheManager;
 7     }
 8 
 9     private final ConcurrentMap<String, Cache> caches;
10 
11     public RedisCacheManager() {
12         caches = new ConcurrentHashMap<String, Cache>();
13     }
14 
15     @SuppressWarnings("unchecked")
16     @Override
17     public <k, v> Cache<k, v> getCache(String name) {
18         Cache cache = caches.get(name);
19         if (cache == null) {
20             cache = new RedisCache<>(compCacheManager, name);
21             caches.put(name, cache);
22         }
23         return cache;
24     }
25 }
View Code

附加两篇文章:

  shiro的认证过程源码分析:https://blog.csdn.net/wn084/article/details/79554486

  shiro的授权过程源码分析:https://blog.csdn.net/wn084/article/details/79563571

代码拉取地址:https://gitee.com/ye_wei/shiro.git

原文地址:https://www.cnblogs.com/step-and-step/p/9991702.html