07月19, 2017

在springmvc中shiro使用redis存储session

使用到的redis KEY:

  • session缓存hash:shiro-cache-authorization
  • session存储value:shiro-cache-session:{sessionId}

ShrioRedisCache

@SuppressWarnings({ "unchecked", "rawtypes" })
public class ShiroRedisCache<HK, HV> implements Cache<HK, HV> {

    private static final LoggerUtil    logger        = LoggerUtil.getLogger(ShiroRedisCache.class);
    private static final String        HASH_CACHE    = "shiro-cache-authorization";
    private final RedisTemplate        _shiroRedisTemplate;

    public ShiroRedisCache(RedisTemplate shiroRedisTemplate) {
        this._shiroRedisTemplate = shiroRedisTemplate;
    }

    private String genCacheKey(Object key) {
        return String.valueOf(key);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.cache.Cache#clear()
     */
    @Override
    public void clear() throws CacheException {
        _shiroRedisTemplate.delete(HASH_CACHE);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.cache.Cache#get(java.lang.Object)
     */
    @Override
    public HV get(HK key) throws CacheException {
        String relKey = genCacheKey(key);
        return (HV) _shiroRedisTemplate.opsForHash().get(HASH_CACHE, relKey);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.cache.Cache#keys()
     */
    @Override
    public Set<HK> keys() {
        return _shiroRedisTemplate.opsForHash().keys(HASH_CACHE);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.cache.Cache#put(java.lang.Object, java.lang.Object)
     */
    @Override
    public HV put(HK key, HV value) throws CacheException {
        HV previos = get(key);
        try {
            logger.info("shiro-redis-cache-put:[{},{}]", key, value);
            _shiroRedisTemplate.opsForHash().put(HASH_CACHE, genCacheKey(key), value);
        } catch (Exception e) {
            logger.error("put cache throw exception", e);
        }
        return previos;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.cache.Cache#remove(java.lang.Object)
     */
    @Override
    public HV remove(HK key) throws CacheException {
        HV previos = get(key);
        logger.info("shiro-redis-cache-remove:[{},{}]", key, previos);
        try {
            _shiroRedisTemplate.opsForHash().delete(HASH_CACHE, genCacheKey(key));
        } catch (Exception e) {
            logger.error("remove cache  throw exception", e);
        }
        return previos;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.cache.Cache#size()
     */
    @Override
    public int size() {
        return _shiroRedisTemplate.opsForHash().size(HASH_CACHE).intValue();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.cache.Cache#values()
     */
    @Override
    public Collection<HV> values() {
        return _shiroRedisTemplate.opsForHash().values(HASH_CACHE);
    }

}

ShiroRedisCacheManager

@SuppressWarnings({ "rawtypes" })
public class ShiroRedisCacheManager implements CacheManager {
    private RedisTemplate _redisTemplate;

    /**
     * @param redisTemplate
     *            the {@link #_redisTemplate} to set
     */
    public void setShiroRedisTemplate(RedisTemplate redisTemplate) {
        this._redisTemplate = redisTemplate;
    }

    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
        return new ShiroRedisCache<K, V>(_redisTemplate);
    }

}

ShiroRedisSessionDao

@SuppressWarnings({ "unchecked", "rawtypes" })
public class ShiroRedisSessionDao extends AbstractSessionDAO {
    private RedisTemplate<Object, Object>    _shiroRedisTemplate;
    private final static String                REDIS_KEY_SHIRO    = "shiro-cache-session:";

    /**
     * @param shiroRedisTemplate
     *            the {@link #_shiroRedisTemplate} to set
     */
    public void setShiroRedisTemplate(RedisTemplate shiroRedisTemplate) {
        this._shiroRedisTemplate = shiroRedisTemplate;
    }

    private String getSessionKey(Serializable sessionId) {
        String preKey = REDIS_KEY_SHIRO + sessionId;
        return preKey;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.session.mgt.eis.SessionDAO#update(org.apache.shiro.
     * session.Session)
     */
    @Override
    public void update(Session session) throws UnknownSessionException {
        if (null == session || null == session.getId()) {
            return;
        }
        String key = getSessionKey(session.getId());
        Long timeOut = session.getTimeout() / 1000;
        _shiroRedisTemplate.opsForValue().set(key, session, timeOut.intValue(), TimeUnit.SECONDS);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.session.mgt.eis.SessionDAO#delete(org.apache.shiro.
     * session.Session)
     */
    @Override
    public void delete(Session session) {
        if (null == session) {
            return;
        }
        Serializable id = session.getId();
        if (id != null) {
            _shiroRedisTemplate.delete(getSessionKey(id));
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.shiro.session.mgt.eis.SessionDAO#getActiveSessions()
     */
    @Override
    public Collection<Session> getActiveSessions() {
        List<Session> sessions = Lists.newLinkedList();
        Set<Object> keys = _shiroRedisTemplate.keys(getSessionKey("*"));
        List<Object> sessDatas = _shiroRedisTemplate.opsForValue().multiGet(keys);
        for (Object _session : sessDatas) {
            if (_session instanceof Session) {
                sessions.add((Session) _session);
            }
        }
        return sessions;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.apache.shiro.session.mgt.eis.AbstractSessionDAO#doCreate(org.apache.
     * shiro.session.Session)
     */
    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        update(session);
        return sessionId;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.apache.shiro.session.mgt.eis.AbstractSessionDAO#doReadSession(java.io
     * .Serializable)
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        String key = getSessionKey(sessionId);
        Object sessionObj = _shiroRedisTemplate.opsForValue().get(key);
        Session _session = null;
        if (sessionObj instanceof Session) {
            _session = (Session) sessionObj;
        }
        return _session;
    }

}

shiro.xml

<!-- 凭证匹配器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="shiroDbRealm" />
        <property name="cacheManager" ref="shiroRedisCacheManager" />
        <!-- redis 缓存 -->
        <property name="sessionManager" ref="defaultWebSessionManager" /> 
    </bean>
    <bean id="defaultWebSessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
         <!-- session存储的实现 -->  
        <property name="sessionDAO" ref="shiroRedisSessionDao" />  
        <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->  
        <property name="sessionIdCookie" ref="shareSession" />
        <!-- 设置全局会话超时时间,默认30分钟(1800000) -->  
        <property name="globalSessionTimeout" value="1800000" />  
        <!-- 是否在会话过期后会调用SessionDAO的delete方法删除会话 默认true -->  
        <property name="deleteInvalidSessions" value="true" />  
        <!-- 会话验证器调度时间 -->  
        <property name="sessionValidationInterval" value="1500000" />  
        <!-- 定时检查失效的session -->  
        <property name="sessionValidationSchedulerEnabled" value="true" /> 
    </bean>
     <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->  
    <bean id="shareSession" class="org.apache.shiro.web.servlet.SimpleCookie">  
        <!-- cookie的name,对应的默认是 JSESSIONID -->  
        <constructor-arg name="name" value="SHAREJSESSIONID" />  
        <!-- jsessionId的path为 / 用于多个系统共享jsessionId -->  
        <property name="path" value="/" />  
        <property name="httpOnly" value="true"/>  
    </bean>
    <bean id="shiroRedisCacheManager" class="ShiroRedisCacheManager">
    <property name="shiroRedisTemplate" ref="shiroRedisTemplate"></property>
    </bean>
    <bean id="shiroRedisSessionDao" class="ShiroRedisSessionDao">
        <property name="shiroRedisTemplate" ref="shiroRedisTemplate"></property>
    </bean>

redis.xml

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.maxActive}" />
        <property name="minIdle" value="${redis.minIdle}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxWaitMillis" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
<bean id="jedisConnectionFactoryShiro"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="usePool" value="true" />
        <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.shiroDb}" />
        <constructor-arg index="0" ref="jedisPoolConfig" />
    </bean>
    <bean id="stringRedisSerializer"
        class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
    <bean id="jdkSerializationRedisSerializer"
        class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
    <bean id="shiroRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactoryShiro" />
        <property name="keySerializer" ref="stringRedisSerializer"></property>
        <property name="hashKeySerializer" ref="stringRedisSerializer"></property>
        <property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
        <property name="hashValueSerializer" ref="jdkSerializationRedisSerializer"></property>
    </bean>

本文链接:https://blog.jnliok.com/post/springmvc-shiro-session-redis.html

-- EOF --

Comments