shiro使用redis缓存session会话、authentication信息、authorization信息简述

3 篇文章 0 订阅
2 篇文章 0 订阅

* 目录 *

介绍

  当我们使用了nginx做负载均衡,使用了多个web服务器时,我们的请求会根据配置的权重信息自动分配到配置的负载服务器上,这时,客户端发起的request并不能指定到同一台web服务器上,这时,shiro默认的ehcache来实现共享缓存比较麻烦,这里直接使用redis做共享缓存,把缓存统一保存在一个地方,这样即可解决web服务器缓存共享问题。
  直接使用web服务器缓存时,如果session会话没有持久化到数据库或者文件中,当web服务器需要升级,这时服务端保存的用户会话session会随着服务器重启而不存在,这时,把session会话保存到redis中也是不错的选择。
  文章将由spring cache配置和shiro使用spring cache代理两个方向进行介绍。

配置

  笔者使用的redisson作为redis客户端,开发者根据实际情况选择,也可以使用jedis,本文只介绍使用redisson实现。

maven依赖

在pom.xml中加入以下依赖信息

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.2.2</version>
</dependency>
spring配置

这里使用注解进行配置,下面为配置代码

@Configuration
@ComponentScan
@EnableCaching
public class WebAppConfig {
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson(@Value("classpath:config/spring-redisson.yaml") Resource configFile) throws IOException {
        Config config = Config.fromYAML(configFile.getInputStream());
        return Redisson.create(config);
    }

    @Bean
    public CacheManager cacheManager(RedissonClient redissonClient) throws IOException {
        return new RedissonSpringCacheManager(redissonClient, "classpath:config/spring-cache-config.yaml");
    }
}
  • spring-redisson.yaml配置文件
    这里直接参考官方配置官方配置中提供完整配置文档(有中文),也提供其他模式(哨兵、主从等)配置方法。
    下面展示单机版配置方式
# redisson configuration for redis servers
# see : https://github.com/mrniko/redisson/wiki/2.-Configuration

singleServerConfig:
  idleConnectionTimeout: 10000
  pingTimeout: 1000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  reconnectionTimeout: 3000
  failedAttempts: 3
  password: null
  subscriptionsPerConnection: 5
  clientName: null
  address: "redis://127.0.0.1:6379"
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  connectionMinimumIdleSize: 10
  connectionPoolSize: 64
  database: 0
  dnsMonitoring: false
  dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
#这里注意,笔者选择的这个序列化工具,官方提供了多种序列化方式,最好不要使用官方提供带Jackson标识的,会出现shiro session存入redis中,但从redis中取出数据时反序列化后session对象中数据丢失,原因未查证。
codec: !<org.redisson.codec.FstCodec> {}
useLinuxNativeEpoll: false

下图中红框标识的默认编码方式不建议使用,shiro session会话反序列化出现问题。
A83D0819-B7BD-4DDD-B7FF-1E9F42A36950.png
- spring-cache-config.yaml配置文件
一定要配置 ttlmaxIdleTime ,都是毫秒。

#权限缓存
authorizationCache:
  ttl: 3600000
  maxIdleTime: 1800000
#认证缓存
authenticationCache:
  ttl: 3600000
  maxIdleTime: 1800000
#session会话缓存
shiro-activeSessionCache:
  ttl: 7200000
  maxIdleTime: 3600000

以上配置成功完成后也就完成了spring cache的配置,可以启动项目测试是否配置成功,测试方法不再列出。

重新实现shiro CacheManager

下面为重新实现shiro CacheManager代码,让shiro缓存使用spring cache代理

/**
省略 package
*/
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;

import java.util.Collection;
import java.util.Set;

public class SpringCacheManagerWrapper implements CacheManager {

    private org.springframework.cache.CacheManager cacheManager;

    /**
     * 设置spring cache manager
     *
     * @param cacheManager spring cache
     */
    public void setCacheManager(org.springframework.cache.CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
        org.springframework.cache.Cache springCache = cacheManager.getCache(name);
        return new SpringCacheWrapper(springCache);
    }

    static class SpringCacheWrapper implements Cache {
        private org.springframework.cache.Cache springCache;

        SpringCacheWrapper(org.springframework.cache.Cache springCache) {
            this.springCache = springCache;
        }

        @Override
        public Object get(Object key) throws CacheException {
            Object value = springCache.get(key);
            if (value instanceof SimpleValueWrapper) {
                return ((SimpleValueWrapper) value).get();
            }
            return value;
        }

        @Override
        public Object put(Object key, Object value) throws CacheException {
            springCache.put(key, value);
            return value;
        }

        @Override
        public Object remove(Object key) throws CacheException {
            springCache.evict(key);
            return null;
        }

        @Override
        public void clear() throws CacheException {
            springCache.clear();
        }

        @Override
        public int size() {
            throw new UnsupportedOperationException("invoke spring cache abstract size method not supported");
        }

        @Override
        public Set keys() {
            throw new UnsupportedOperationException("invoke spring cache abstract keys method not supported");
        }

        @Override
        public Collection values() {
            throw new UnsupportedOperationException("invoke spring cache abstract values method not supported");
        }
    }
}
shiro缓存配置

这里暂时采用xml配置文件,下面为xml部分配置文件

<bean id="shiroCacheManager" class="com.fangshuo.basic.shiro.cache.spring.SpringCacheManagerWrapper">
    <property name="cacheManager" ref="cacheManager"/>
</bean>

<!-- Realm实现 -->
<bean id="userRealm" class="com.fangshuo.basic.shiro.realm.VUserRealm">
    <!-- 凭证匹配器省略 credentialsMatcher -->
    <property name="cacheManager" ref="shiroCacheManager"/>
    <property name="cachingEnabled" value="false"/>
    <property name="authenticationCachingEnabled" value="true"/>
    <property name="authenticationCacheName" value="authenticationCache"/>
    <property name="authorizationCachingEnabled" value="true"/>
    <property name="authorizationCacheName" value="authorizationCache"/>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!--省略其他配置信息,这里只介绍缓存 -->
    <property name="cacheManager" ref="shiroCacheManager"/>
</bean>

上面为配置信息,其实只需要把以前使用shiro的缓存实现改为我们实现的即可。
如果使用了shiro提供的SimpleCookie类,maxAge参数设置为-1,redis会自动过期session,不在需要shiro管理session会话时间。

其他说明

如果出现错误,错误信息显示SimpleByteSource类没有实现Serializable,这个时候我们需要重写一些SimpleByteSource类,例如:

import org.apache.shiro.util.SimpleByteSource;

import java.io.Serializable;

/**
 * @author Created by yangyang on 2017/1/7.
 *         e-mail :yangyang_666@icloud.com ; tel :18580128658 ;QQ :296604153
 */
public class MySimpleByteSource extends SimpleByteSource implements Serializable {

    public MySimpleByteSource(byte[] bytes) {
        super(bytes);
    }

    public MySimpleByteSource(String string) {
        super(string);
    }
}

只需要继承SimpleByteSource并实现Serializable,构造方法根据实际情况添加。
备注:如果使用了shiro的认证匹配器,可能会用到此类。

测试

完成以上配置步骤,直接启动项目,进行登录,然后进入redis,成功标识请见下图
444A4C76-3EC5-4243-88A6-233DDCFD9D34.png

总结

  使用独立缓存服务器,可以保证服务在重启的时候,用户不会受到服务器重启后session消失的影响,在存在大量session会话的情况下也不会导致web服务内存溢出等问题,也可以保证使用多个web服务器负载时,session共享。如果文章描述出现问题,请联系笔者修改。
原创文章,转载请注明出处

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值