shiro框架实现基于redis的SessionDao

1 篇文章 0 订阅

今天有个项目要从单机改成分布式部署,但是安全框架shiro只有单机存储的SessionDao。

于是自己实现了个基于redis存储的SessionDao。

配置文件:

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxIdle" value="${redis.maxIdle}" />
		<property name="maxActive" value="${redis.maxActive}" />
		<property name="maxWait" value="${redis.maxWait}" />
		<property name="testOnBorrow" value="${redis.testOnBorrow}" />
	</bean>
	<!-- spring data redis -->
	<bean id="jedisConnectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<property name="usePool" value="true"></property>
		<property name="hostName" value="${redis.host}" />
		<property name="port" value="${redis.port}" />
		<property name="password" value="${redis.pass}" />
		<property name="timeout" value="${redis.timeout}" />
		<property name="database" value="${redis.default.db}"></property>
		<constructor-arg index="0" ref="jedisPoolConfig" />
	</bean>


	<bean name="redisTemplate"
		class="org.springframework.data.redis.core.StringRedisTemplate"
		lazy-init="false">
		<property name="connectionFactory" ref="jedisConnectionFactory" />
	</bean>

 

shiro配置:

 

<!-- session管理器 -->
	<bean id="sessionManager"
		class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<!-- 超时时间 -->
		<property name="globalSessionTimeout" value="7200000" />
		<!-- session存储的实现 -->
		<property name="sessionDAO" ref="collectionRedisSessionDao" />
		<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
		<property name="sessionIdCookie" ref="sharesession" />
		<!-- 定时检查失效的session -->
		<property name="sessionValidationSchedulerEnabled" value="true" />
	</bean>

主要还是引用自己写的sessionDao。

CollectionSessionDao.java


import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;

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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@SuppressWarnings({"rawtypes","unchecked"})
@Component("collectionRedisSessionDao")
@Lazy(false)
public class CollectionRedisSessionDao extends AbstractSessionDAO {
	private static Logger logger = LoggerFactory.getLogger(CollectionRedisSessionDao.class);
	@Autowired
	private RedisTemplate redisTemplate;
	@Value("${redis.key.prefix}")
	private String redisPrefixKey;
	/**
	 * The Redis key prefix for the sessions
	 */
	private String keyPrefix = "shiro_redis_session:";
	private String getKey(String originalKey) {
		return redisPrefixKey + keyPrefix+originalKey;
	}
	@PostConstruct
	public void init(){
		logger.info("注入催收的序列/反序列类");
		CollectionSerializer<Serializable> collectionSerializer=CollectionSerializer.getInstance();
		redisTemplate.setDefaultSerializer(collectionSerializer);
		//redisTemplate默认采用的其实是valueSerializer,就算是采用其他ops也一样,这是一个坑。
		redisTemplate.setValueSerializer(collectionSerializer);
	}
	
	@Override
	public void update(Session session) throws UnknownSessionException {
		logger.debug("更新seesion,id=[{}]", session.getId().toString());
		try {
			redisTemplate.opsForValue().set(getKey(session.getId().toString()), session,30,TimeUnit.MINUTES);
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
	}

	@Override
	public void delete(Session session) {
		logger.debug("删除seesion,id=[{}]", session.getId().toString());
		try {
			String key=getKey(session.getId().toString());
			redisTemplate.delete(key);
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
		}

	}

	@Override
	public Collection<Session> getActiveSessions() {
		logger.info("获取存活的session");
		return Collections.emptySet();
	}

	@Override
	protected Serializable doCreate(Session session) {
		Serializable sessionId = generateSessionId(session);
		assignSessionId(session, sessionId);
		logger.debug("创建seesion,id=[{}]", session.getId().toString());
		try {
			redisTemplate.opsForValue().set(getKey(session.getId().toString()), session,30,TimeUnit.MINUTES);
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		return sessionId;
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {

		logger.debug("获取seesion,id=[{}]", sessionId.toString());
		Session readSession = null;
		try {
			readSession=(Session) redisTemplate.opsForValue().get(getKey(sessionId.toString()));
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return readSession;
	}
	
	
}

由于redisTemplate自带的序列和反序列化类不能满足需求,于是也要自己写一个

CollectionSerializer.java

 



import org.apache.commons.lang3.SerializationUtils;
import java.io.Serializable;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
/**
 * 自己实现的序列/反序列类
 * @author XieZG
 * @Date 2017年3月9日下午2:06:52 
 * @param <T>
 */
public class CollectionSerializer<T extends Serializable> implements RedisSerializer<T>{
	private CollectionSerializer(){}
	public static volatile CollectionSerializer<Serializable> collectionSerializer=null;
	public static CollectionSerializer<Serializable> getInstance(){
		if(collectionSerializer==null){
			synchronized (CollectionSerializer.class) {
				if(collectionSerializer==null){
					collectionSerializer=new CollectionSerializer<>();
				}
			}
		}
		return collectionSerializer;
	}
	@Override
	public byte[] serialize(T t) throws SerializationException {
		return SerializationUtils.serialize(t);
	}

	@Override
	public T deserialize(byte[] bytes) throws SerializationException {
		return SerializationUtils.deserialize(bytes);
	}


}

 

 

以上,完成。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山间明月江上清风_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值