zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    <2014 04 29> *nix环境编程常用库总结
    <2014 04 29> c/c++常用库总结
    <2014 04 26> 《Coders at Work编程人生:15位软件先驱访谈录》
    <2014 04 16> 上班实习第一天
    <2014 04 15> C++语言回顾精要(原创By Andrew)
    [荐][转]为何应该使用 MacOS X(论GUI环境下开发人员对软件的配置与重用)
    [荐][转]王垠:我和权威的故事(2014)
    [荐][转]如何用美剧真正提升你的英语水平
    [转] 数学的用处(一)(二)(三)(四)(数学图谱)
    metadata 和 routing
  • 原文地址:https://www.cnblogs.com/step-and-step/p/9991702.html
Copyright © 2011-2022 走看看