shiro 在集群环境下用redis(集群版)做session共享

如今集群环境已是服务器主流,在集群环境中,session共享一般通过应用服务器的session复制或者存储在公用的缓存服务器上,本文主要介绍通过Shiro管理session,并将session缓存到redis集群版中,这样可以在集群中使用。

Shiro除了在管理session上使用redis,也在可以缓存用户权限,即cacheManager可以通过redis来扩展。

下面从 sessionManager这部分讲解Shiro与Redis的集成,

先看下配置问件:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!-- 装配 securityManager --><!-- 注入安全管理对象 --><!-- 配置登陆页面 --><!-- 登陆成功后的一面 --><!-- 权限不足页面 --><!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截. --><!-- /cityparlor/home/index.html=authc -->  
  3.                 /cityparlor/cityparlor/**=anon  
  4.                 /cityparlor/**=authc  
  5.                 /common/**=anon  
  6.             <!-- 配置缓存管理器 --><!-- 指定 ehcache 的配置文件 --><!-- 配置进行授权和认证的 Realm --><!-- 配置 Shiro 的 SecurityManager Bean. --><!-- sessionManager --><!-- <property name="cacheManager" ref="mycacheManager" /> --><!-- 要想完成redis代理session 此配置很重要--><!-- sessionManager --><!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID --><!-- 设置全局会话超时时间,默认30分钟(1800000) --><!-- 是否在会话过期后会调用SessionDAO的delete方法删除会话 默认true --><!-- 会话验证器调度时间 --><!-- 定时检查失效的session --><!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID --><!-- cookie的name,对应的默认是 JSESSIONID --><!-- jsessionId的path为 / 用于多个系统共享jsessionId --><!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. --><!-- 保证实现了Shiro内部lifecycle函数的bean执行 --><!-- <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> --><!-- AOP式方法级权限检查 --><!-- 切面 -->  

shiro框架中有一个对session配置管理对象:sessionManager对象,对象中可注入对象参数:sessionDAO,源码如下:


此SessionDao中封装内容如下:


不难发现,里面封装的就是对session的增删改查,因此我们只需对sessionDao进行自己的继承,实现类即可;

自己封装代码如下:

[java]  view plain  copy
  1. package com.cityparlor.web.admin.realm;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.Collection;  
  5. import java.util.HashSet;  
  6. import java.util.Set;  
  7.   
  8. import org.apache.shiro.session.Session;  
  9. import org.apache.shiro.session.UnknownSessionException;  
  10. import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;  
  11. import org.slf4j.Logger;  
  12. import org.slf4j.LoggerFactory;  
  13.   
  14. import com.cityparlor.common.utils.JedisUtils;  
  15.   
  16. public class RedisSessionDAO extends AbstractSessionDAO{  
  17.     private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);  
  18.     /*private JedisUtils redisManager;*/  
  19.     private String keyPrefix;  
  20.     private int expire = 0;  
  21.       
  22.   
  23.     public RedisSessionDAO() {  
  24.         this.keyPrefix = "shiro_redis_session:";  
  25.     }  
  26.   
  27.     @Override  
  28.     public void update(Session session) throws UnknownSessionException {  
  29.         // TODO Auto-generated method stub  
  30.         this.saveSession(session);  
  31.     }  
  32.       
  33.     /** 
  34.      * 获取序列化字节id 
  35.      * TODO 
  36.      * @param sessionId 
  37.      * @return<br> 
  38.      * ============History===========<br> 
  39.      * 2017年7月17日   LHL    新建 
  40.      */  
  41.     /*private byte[] getByteKey(Serializable sessionId) { 
  42.         String preKey = this.keyPrefix + sessionId; 
  43.         return preKey.getBytes(); 
  44.     }*/  
  45.     private String getKey(Serializable sessionId) {  
  46.         String preKey = this.keyPrefix + sessionId;  
  47.         return preKey;  
  48.     }  
  49.       
  50.     private void saveSession(Session session) throws UnknownSessionException {  
  51.         if ((session == null) || (session.getId() == null)) {  
  52.             logger.error("session or session id is null");  
  53.             return;  
  54.         }  
  55.   
  56.         String key = getKey(session.getId());  
  57.         /*byte[] value = SerializeUtils.serialize(session);*/  
  58.         session.setTimeout(expire * 1000);  
  59.         JedisUtils.setObject(key, session, this.expire);//this.redisManager.set(key, value, this.redisManager.getExpire());  
  60.     }  
  61.       
  62.       
  63.     @Override  
  64.     public void delete(Session session) {  
  65.         if ((session == null) || (session.getId() == null)) {  
  66.             logger.error("session or session id is null");  
  67.             return;  
  68.         }  
  69.         JedisUtils.delObject(getKey(session.getId()));//this.redisManager.del(getByteKey(session.getId()));  
  70.           
  71.     }  
  72.   
  73.     @Override  
  74.     public Collection getActiveSessions() {  
  75.         // TODO Auto-generated method stub  
  76.         Set sessions = new HashSet();  
  77.   
  78.         Set keys = JedisUtils.keys(this.keyPrefix + "*");  
  79.         if ((keys != null) && (keys.size() > 0)) {  
  80.             for (String key : keys) {  
  81.                 Session s = (Session) JedisUtils.getObject(key);// (Session) SerializeUtils.deserialize(this.redisManager.get(key));  
  82.                 sessions.add(s);  
  83.             }  
  84.         }  
  85.   
  86.         return sessions;  
  87.     }  
  88.   
  89.     @Override  
  90.     protected Serializable doCreate(Session session) {  
  91.         // TODO Auto-generated method stub  
  92.         Serializable sessionId = generateSessionId(session);  
  93.         assignSessionId(session, sessionId);  
  94.         saveSession(session);  
  95.         return sessionId;  
  96.     }  
  97.   
  98.     @Override  
  99.     protected Session doReadSession(Serializable sessionId) {  
  100.         // TODO Auto-generated method stub  
  101.         if (sessionId == null) {  
  102.             logger.error("session id is null");  
  103.             return null;  
  104.         }  
  105.   
  106.         Session s =(Session) JedisUtils.getObject(getKey(sessionId)) ;// SerializeUtils.deserialize(this.redisManager.get(getByteKey(sessionId)));  
  107.         return s;  
  108.     }  
  109.   
  110. }  
这里我们只是将session的增删改查换成了用redis的增删改查;
redis链接工具类代码如下:
[java]  view plain  copy
  1. /** 
  2.  *  
  3.  */  
  4. package com.cityparlor.common.utils;  
  5.   
  6. import java.util.List;  
  7. import java.util.Map;  
  8. import java.util.Set;  
  9. import java.util.TreeSet;  
  10.   
  11. import org.slf4j.Logger;  
  12. import org.slf4j.LoggerFactory;  
  13.   
  14. import com.cityparlor.common.config.Global;  
  15. import com.google.common.collect.Lists;  
  16. import com.google.common.collect.Maps;  
  17. import com.google.common.collect.Sets;  
  18.   
  19. import redis.clients.jedis.Jedis;  
  20. import redis.clients.jedis.JedisCluster;  
  21. import redis.clients.jedis.JedisPool;  
  22.   
  23. /** 
  24.  * Jedis Cache 工具类 
  25.  *  
  26.  * @author Administrator 
  27.  * @version 2015-09-29 
  28.  */  
  29. public class JedisUtils {  
  30.   
  31.     private static Logger logger = LoggerFactory.getLogger(JedisUtils.class);  
  32.       
  33.     private static JedisCluster jedisCluster = SpringContextHolder.getBean(JedisCluster.class);  
  34.     //private static JedisPool jedisPool = SpringContextHolder.getBean(JedisPool.class);  
  35.   
  36.     public static final String KEY_PREFIX = Global.getConfig("redis.keyPrefix");  
  37.       
  38.     /** 
  39.      * 利用redis 生成自增长的长整形主键 
  40.      * */  
  41.       
  42.       
  43.     /** 
  44.      * 获取所有keys 
  45.      * TODO 
  46.      * @param pattern 
  47.      * @return<br> 
  48.      * ============History===========<br> 
  49.      * 2017年7月17日   LHL    新建 
  50.      */  
  51.      public static TreeSet keys(String pattern){    
  52.             //logger.debug("Start getting keys...");    
  53.             TreeSet keys = new TreeSet<>();    
  54.             Map clusterNodes = jedisCluster.getClusterNodes();    
  55.             for(String k : clusterNodes.keySet()){    
  56.              //   logger.debug("Getting keys from: {}", k);    
  57.                 JedisPool jp = clusterNodes.get(k);    
  58.                 Jedis connection = jp.getResource();    
  59.                 try {    
  60.                     keys.addAll(connection.keys(pattern));    
  61.                 } catch(Exception e){    
  62.                     logger.error("Getting keys error: {}", e);    
  63.                 } finally{    
  64.                     logger.debug("Connection closed.");    
  65.                     connection.close();//用完一定要close这个链接!!!    
  66.                 }    
  67.             }    
  68.            // logger.debug("Keys gotten!");    
  69.             return keys;    
  70.         }    
  71.     /** 
  72.      * 获取缓存 
  73.      * @param key 键 
  74.      * @return 值 
  75.      */  
  76.     public static String get(String key) {  
  77.         key = KEY_PREFIX + key;  
  78.         String value = null;  
  79.         //Jedis jedis = null;  
  80.         try {  
  81.             //jedis = getResource();  
  82.             if (jedisCluster.exists(key)) {  
  83.                 value = jedisCluster.get(key);  
  84.                 value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null;  
  85.                 logger.debug("get {} = {}", key, value);  
  86.             }  
  87.         } catch (Exception e) {  
  88.             logger.warn("get {} = {}", key, value, e);  
  89.         } finally {  
  90.             //returnResource(jedis);  
  91.         }  
  92.         return value;  
  93.     }  
  94.       
  95.     /** 
  96.      * 获取缓存 
  97.      * @param key 键 
  98.      * @return 值 
  99.      */  
  100.     public static Object getObject(String key) {  
  101.         key = KEY_PREFIX + key;  
  102.         Object value = null;  
  103.         //Jedis jedis = null;  
  104.         try {  
  105.             //jedis = getResource();  
  106.             if (jedisCluster.exists(getBytesKey(key))) {  
  107.                 value = toObject(jedisCluster.get(getBytesKey(key)));  
  108.                 logger.debug("getObject {} = {}", key, value);  
  109.             }  
  110.         } catch (Exception e) {  
  111.             logger.warn("getObject {} = {}", key, value, e);  
  112.         } finally {  
  113.             //returnResource(jedis);  
  114.         }  
  115.         return value;  
  116.     }  
  117.       
  118.     /** 
  119.      * 设置缓存,利用setex 
  120.      * @param key 
  121.      * @param seconds 
  122.      * @param value 
  123.      * @return 
  124.      */  
  125.     public static String setex(String key, int seconds, String value){  
  126.         key = KEY_PREFIX + key;  
  127.         String result = null;  
  128.         //Jedis jedis = null;  
  129.         try {  
  130.             //jedis = getResource();  
  131.             result = jedisCluster.setex(key, seconds, value);  
  132.             logger.debug("setex {} = {}", key, value);  
  133.         } catch (Exception e) {  
  134.             logger.warn("setex {} = {}", key, value, e);  
  135.         } finally {  
  136.             //returnResource(jedis);  
  137.         }  
  138.         return result;  
  139.     }  
  140.       
  141.     /** 
  142.      * 设置缓存 
  143.      * @param key 键 
  144.      * @param value 值 
  145.      * @param cacheSeconds 超时时间,0为不超时 
  146.      * @return 
  147.      */  
  148.     public static String set(String key, String value, int cacheSeconds) {  
  149.         key = KEY_PREFIX + key;  
  150.         String result = null;  
  151.         //Jedis jedis = null;  
  152.         try {  
  153.             //jedis = getResource();  
  154.             result = jedisCluster.set(key, value);  
  155.             if (cacheSeconds != 0) {  
  156.                 jedisCluster.expire(key, cacheSeconds);  
  157.             }  
  158.             logger.debug("set {} = {}", key, value);  
  159.         } catch (Exception e) {  
  160.             logger.warn("set {} = {}", key, value, e);  
  161.         } finally {  
  162.             //returnResource(jedis);  
  163.         }  
  164.         return result;  
  165.     }  
  166.       
  167.     /** 
  168.      * 设置缓存 
  169.      * @param key 键 
  170.      * @param value 值 
  171.      * @param cacheSeconds 超时时间,0为不超时 
  172.      * @return 
  173.      */  
  174.     public static String setObject(String key, Object value, int cacheSeconds) {  
  175.         key = KEY_PREFIX + key;  
  176.         String result = null;  
  177.         //Jedis jedis = null;  
  178.         try {  
  179.             //jedis = getResource();  
  180.             result = jedisCluster.set(getBytesKey(key), toBytes(value));  
  181.             if (cacheSeconds != 0) {  
  182.                 jedisCluster.expire(key, cacheSeconds);  
  183.             }  
  184.             logger.debug("setObject {} = {}", key, value);  
  185.         } catch (Exception e) {  
  186.             logger.warn("setObject {} = {}", key, value, e);  
  187.         } finally {  
  188.             //returnResource(jedis);  
  189.         }  
  190.         return result;  
  191.     }  
  192.       
  193.     /** 
  194.      * 获取List缓存 
  195.      * @param key 键 
  196.      * @return 值 
  197.      */  
  198.     public static List getList(String key) {  
  199.         key = KEY_PREFIX + key;  
  200.         List value = null;  
  201.         //Jedis jedis = null;  
  202.         try {  
  203.             //jedis = getResource();  
  204.             if (jedisCluster.exists(key)) {  
  205.                 value = jedisCluster.lrange(key, 0, -1);  
  206.                 logger.debug("getList {} = {}", key, value);  
  207.             }  
  208.         } catch (Exception e) {  
  209.             logger.warn("getList {} = {}", key, value, e);  
  210.         } finally {  
  211.             //returnResource(jedis);  
  212.         }  
  213.         return value;  
  214.     }  
  215.       
  216.     /** 
  217.      * 获取List缓存 
  218.      * @param key 键 
  219.      * @return 值 
  220.      */  
  221.     public static List  
对redis链接池的封装也可按自己的来,只要将自己实现的RedisSessionDAO中的方法重新定义即可;

猜你喜欢

转载自blog.csdn.net/qq_36838191/article/details/80202369
今日推荐