shiro 在集群环境下用redis(集群版)做session共享
如今集群环境已是服务器主流,在集群环境中,session共享一般通过应用服务器的session复制或者存储在公用的缓存服务器上,本文主要介绍通过Shiro管理session,并将session缓存到redis集群版中,这样可以在集群中使用。
Shiro除了在管理session上使用redis,也在可以缓存用户权限,即cacheManager可以通过redis来扩展。
下面从 sessionManager这部分讲解Shiro与Redis的集成,
先看下配置问件:
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- 装配 securityManager --><!-- 注入安全管理对象 --><!-- 配置登陆页面 --><!-- 登陆成功后的一面 --><!-- 权限不足页面 --><!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截. --><!-- /cityparlor/home/index.html=authc -->
- /cityparlor/cityparlor/**=anon
- /cityparlor/**=authc
- /common/**=anon
- <!-- 配置缓存管理器 --><!-- 指定 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进行自己的继承,实现类即可;
自己封装代码如下:
- 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<br>
- * ============History===========<br>
- * 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<br>
- * ============History===========<br>
- * 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