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

时间:2021-02-16 17:40:40

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

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

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

先看下配置问件:

<?xml version="1.0" encoding="UTF-8"?>

   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
				/cityparlor/cityparlor/**=anon
				/cityparlor/**=authc
				/common/**=anon
			
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  
   
   
  
  

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

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

此SessionDao中封装内容如下:

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

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

自己封装代码如下:

package com.cityparlor.web.admin.realm;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cityparlor.common.utils.JedisUtils;

public class RedisSessionDAO extends AbstractSessionDAO{
	private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
	/*private JedisUtils redisManager;*/
	private String keyPrefix;
	private int expire = 0;
	

	public RedisSessionDAO() {
		this.keyPrefix = "shiro_redis_session:";
	}

	@Override
	public void update(Session session) throws UnknownSessionException {
		// TODO Auto-generated method stub
		this.saveSession(session);
	}
	
	/**
	 * 获取序列化字节id
	 * TODO
	 * @param sessionId
	 * @return
* ============History===========
* 2017年7月17日 LHL 新建 */ /*private byte[] getByteKey(Serializable sessionId) { String preKey = this.keyPrefix + sessionId; return preKey.getBytes(); }*/ private String getKey(Serializable sessionId) { String preKey = this.keyPrefix + sessionId; return preKey; } private void saveSession(Session session) throws UnknownSessionException { if ((session == null) || (session.getId() == null)) { logger.error("session or session id is null"); return; } String key = getKey(session.getId()); /*byte[] value = SerializeUtils.serialize(session);*/ session.setTimeout(expire * 1000); JedisUtils.setObject(key, session, this.expire);//this.redisManager.set(key, value, this.redisManager.getExpire()); } @Override public void delete(Session session) { if ((session == null) || (session.getId() == null)) { logger.error("session or session id is null"); return; } JedisUtils.delObject(getKey(session.getId()));//this.redisManager.del(getByteKey(session.getId())); } @Override public Collection getActiveSessions() { // TODO Auto-generated method stub Set sessions = new HashSet(); Set keys = JedisUtils.keys(this.keyPrefix + "*"); if ((keys != null) && (keys.size() > 0)) { for (String key : keys) { Session s = (Session) JedisUtils.getObject(key);// (Session) SerializeUtils.deserialize(this.redisManager.get(key)); sessions.add(s); } } return sessions; } @Override protected Serializable doCreate(Session session) { // TODO Auto-generated method stub Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); saveSession(session); return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { // TODO Auto-generated method stub if (sessionId == null) { logger.error("session id is null"); return null; } Session s =(Session) JedisUtils.getObject(getKey(sessionId)) ;// SerializeUtils.deserialize(this.redisManager.get(getByteKey(sessionId))); return s; } }
这里我们只是将session的增删改查换成了用redis的增删改查;
redis链接工具类代码如下:
/**
 * 
 */
package com.cityparlor.common.utils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cityparlor.common.config.Global;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;

/**
 * Jedis Cache 工具类
 * 
 * @author Administrator
 * @version 2015-09-29
 */
public class JedisUtils {

	private static Logger logger = LoggerFactory.getLogger(JedisUtils.class);
	
	private static JedisCluster jedisCluster = SpringContextHolder.getBean(JedisCluster.class);
	//private static JedisPool jedisPool = SpringContextHolder.getBean(JedisPool.class);

	public static final String KEY_PREFIX = Global.getConfig("redis.keyPrefix");
	
	/**
	 * 利用redis 生成自增长的长整形主键
	 * */
	
	
	/**
	 * 获取所有keys
	 * TODO
	 * @param pattern
	 * @return
* ============History===========
* 2017年7月17日 LHL 新建 */ public static TreeSet keys(String pattern){ //logger.debug("Start getting keys..."); TreeSet keys = new TreeSet<>(); Map clusterNodes = jedisCluster.getClusterNodes(); for(String k : clusterNodes.keySet()){ // logger.debug("Getting keys from: {}", k); JedisPool jp = clusterNodes.get(k); Jedis connection = jp.getResource(); try { keys.addAll(connection.keys(pattern)); } catch(Exception e){ logger.error("Getting keys error: {}", e); } finally{ logger.debug("Connection closed."); connection.close();//用完一定要close这个链接!!! } } // logger.debug("Keys gotten!"); return keys; } /** * 获取缓存 * @param key 键 * @return 值 */ public static String get(String key) { key = KEY_PREFIX + key; String value = null; //Jedis jedis = null; try { //jedis = getResource(); if (jedisCluster.exists(key)) { value = jedisCluster.get(key); value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null; logger.debug("get {} = {}", key, value); } } catch (Exception e) { logger.warn("get {} = {}", key, value, e); } finally { //returnResource(jedis); } return value; } /** * 获取缓存 * @param key 键 * @return 值 */ public static Object getObject(String key) { key = KEY_PREFIX + key; Object value = null; //Jedis jedis = null; try { //jedis = getResource(); if (jedisCluster.exists(getBytesKey(key))) { value = toObject(jedisCluster.get(getBytesKey(key))); logger.debug("getObject {} = {}", key, value); } } catch (Exception e) { logger.warn("getObject {} = {}", key, value, e); } finally { //returnResource(jedis); } return value; } /** * 设置缓存,利用setex * @param key * @param seconds * @param value * @return */ public static String setex(String key, int seconds, String value){ key = KEY_PREFIX + key; String result = null; //Jedis jedis = null; try { //jedis = getResource(); result = jedisCluster.setex(key, seconds, value); logger.debug("setex {} = {}", key, value); } catch (Exception e) { logger.warn("setex {} = {}", key, value, e); } finally { //returnResource(jedis); } return result; } /** * 设置缓存 * @param key 键 * @param value 值 * @param cacheSeconds 超时时间,0为不超时 * @return */ public static String set(String key, String value, int cacheSeconds) { key = KEY_PREFIX + key; String result = null; //Jedis jedis = null; try { //jedis = getResource(); result = jedisCluster.set(key, value); if (cacheSeconds != 0) { jedisCluster.expire(key, cacheSeconds); } logger.debug("set {} = {}", key, value); } catch (Exception e) { logger.warn("set {} = {}", key, value, e); } finally { //returnResource(jedis); } return result; } /** * 设置缓存 * @param key 键 * @param value 值 * @param cacheSeconds 超时时间,0为不超时 * @return */ public static String setObject(String key, Object value, int cacheSeconds) { key = KEY_PREFIX + key; String result = null; //Jedis jedis = null; try { //jedis = getResource(); result = jedisCluster.set(getBytesKey(key), toBytes(value)); if (cacheSeconds != 0) { jedisCluster.expire(key, cacheSeconds); } logger.debug("setObject {} = {}", key, value); } catch (Exception e) { logger.warn("setObject {} = {}", key, value, e); } finally { //returnResource(jedis); } return result; } /** * 获取List缓存 * @param key 键 * @return 值 */ public static List getList(String key) { key = KEY_PREFIX + key; List value = null; //Jedis jedis = null; try { //jedis = getResource(); if (jedisCluster.exists(key)) { value = jedisCluster.lrange(key, 0, -1); logger.debug("getList {} = {}", key, value); } } catch (Exception e) { logger.warn("getList {} = {}", key, value, e); } finally { //returnResource(jedis); } return value; } /** * 获取List缓存 * @param key 键 * @return 值 */ public static List
对redis链接池的封装也可按自己的来,只要将自己实现的RedisSessionDAO中的方法重新定义即可;

文章不够详细,如有深究可以参考:http://blog.csdn.net/lishehe/article/details/45224181;