# shiro-redis
**Repository Path**: BYSRepo/shiro-redis
## Basic Information
- **Project Name**: shiro-redis
- **Description**: 基于Redis的shiro集中式缓存解决方案
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 392
- **Forks**: 126
- **Created**: 2016-04-13
- **Last Updated**: 2025-02-10
## Categories & Tags
**Categories**: cache-modules
**Tags**: None
## README
##  Shiro-Redis
Shiro集成Redis的适配器,为解决shiro-ehcache不利于集群而打造的集中式缓存方案。
[](https://www.apache.org/licenses/LICENSE-2.0.html)
[](https://mvnrepository.com/artifact/org.iherus.shiro/shiro-redis)
**Maven坐标**
```
org.iherus.shiro
shiro-redis
2.5.0
```
SpringBoot:
```
org.iherus.shiro
shiro-redis-spring-boot-web-starter
2.5.0
```
## 更新日志
**v2.5.0:**
**Change Log**
1)解决Issues:[#I1YUFN](https://gitee.com/iherus/shiro-redis/issues/I1YUFN)、[#I2BSCN](https://gitee.com/iherus/shiro-redis/issues/I2BSCN)、
[#I2B7LC](https://gitee.com/iherus/shiro-redis/issues/I2B7LC)、[#I22K17](https://gitee.com/iherus/shiro-redis/issues/I22K17)、[#I26UHZ](https://gitee.com/iherus/shiro-redis/issues/I26UHZ)。
2)支持session永不失效,[#I2BCKL](https://gitee.com/iherus/shiro-redis/issues/I2BCKL) 。
~~**v2.4.0:【存在bug,请忽略此版本】**
~~
常规bug fix 版本
**v2.3.0:**
**Change Log**
1)解决RedisSessionDAO#uncache方法抛出StackOverflowError。Issues:[#I1TIIG](https://gitee.com/iherus/shiro-redis/issues/I1TIIG)
2)依赖升级,其中Shiro的版本升至1.6.0。
**v2.2.0:**
**Change Log**
1)加入scope策略.
**v2.1.0:**
**Change Log**
1)修复bug.
2)增强兼容性
3)发布[shiro-redis-spring-boot-web-starter](https://gitee.com/iherus/shiro-redis-spring-boot-web-starter)
**v2.0.0:**
**Note**
此版本为重构版本,API不兼容v1.x。
**Change Log**
1)在v1.x仅支持单机模式的基础上,新增了对 哨兵(Sentinel)、集群(Cluster)模式的支持。
2)支持Lettuce客户端、Redisson客户端
3)兼容Spring-data-redis
4)非集群模式,可设置独立的database
5)支持设置缓存失效时间
6)优化性能
7)新增RedisSessionDAO用于降低请求Redis的频率
## Shiro-Redis使用说明
**1、基于ini的使用方式**
```
[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=MD5
#散列次数
credentialsMatcher.hashIterations=2
#定义缓存池配置
poolConfig=redis.clients.jedis.JedisPoolConfig
poolConfig.minIdle=3
poolConfig.maxIdle=10
poolConfig.maxWaitMillis=1500
poolConfig.maxTotal=100
#定义连接配置
## Standalone
configuration=org.iherus.shiro.cache.redis.config.RedisStandaloneConfiguration
configuration.host=127.0.0.1
configuration.port=6379
configuration.database=2
#configuration.password=
## Sentinel
#configuration=org.iherus.shiro.cache.redis.config.RedisSentinelConfiguration
#configuration.masterName=mymaster
#configuration.sentinelsFromText=127.0.0.1:56379,127.0.0.1:56479,127.0.0.1:56579
#configuration.database=2
#configuration.password=
## Cluster
#configuration=org.iherus.shiro.cache.redis.config.RedisClusterConfiguration
#configuration.clusterNodesFromText=127.0.0.1:16379, 127.0.0.1:16380, 127.0.0.1:16381, 127.0.0.1:16382, 127.0.0.1:16383, 127.0.0.1:16384
#configuration.password=
#定义连接工厂
## Jedis
connectionFactory=org.iherus.shiro.cache.redis.connection.jedis.JedisConnectionFactory
connectionFactory.poolConfig=$poolConfig
connectionFactory.configuration=$configuration
#connectionFactory.clientName=
#connectionFactory.connectTimeoutMillis=
#connectionFactory.soTimeoutMillis=
## Lettuce
#connectionFactory=org.iherus.shiro.cache.redis.connection.lettuce.LettuceConnectionFactory
#connectionFactory.poolConfig=$poolConfig
#connectionFactory.configuration=$configuration
#connectionFactory.clientName=
#connectionFactory.timeoutMillis=
## Redisson
#connectionFactory=org.iherus.shiro.cache.redis.connection.redisson.RedissonConnectionFactory
#connectionFactory.configuration=$configuration
#connectionFactory.clientName=
#connectionFactory.connectTimeoutMillis=
#connectionFactory.soTimeoutMillis=
#定义缓存管理器
cacheManager=org.iherus.shiro.cache.redis.RedisCacheManager
cacheManager.connectionFactory=$connectionFactory
cacheManager.expirationMillis=900000
cacheManager.keyPrefix=shiro:test:cache:
#cacheManager.scanBatchSize=3000
#cacheManager.deleteBatchSize=5000
#cacheManager.fetchBatchSize=50
#cacheManager.database=5
#将凭证匹配器设置到realm
customRealm=org.iherus.shiro.tester.CustomRealm
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm
securityManager.cacheManager=$cacheManager
```
详细测试代码请看:src/test/java/org/iherus/shiro /tester/SimpleCacheTest.java
**2、Spring集成的方式**
```
```
**3、Spring Boot集成的方式**
3-1)引入Spring Boot Starter依赖项:
```
org.iherus.shiro
shiro-redis-spring-boot-web-starter
{latestVersion}
```
$\color{red}{注意:由于客户端工具是可选依赖,所以,请根据需要引入相应依赖,支持jedis、lettuce、redisson和spring-data-redis,}$
$\color{red}{如若使用lettuce,还需要再引入commons-pool2。}$
3-2)默认情况下,shiro-redis-spring-boot-web-starter会自动创建 RedisCacheManager 和 RedisSessionDAO 实例并注入 WebSecurityManager 和 WebSessionManager中,如果您需要自定义 SecurityManager 和 SessionManager。
示例如下:
```
@Bean
public SessionManager sessionManager(SessionDAO sessionDAO) {
DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager();
// 注入RedisSessionDAO实例
webSessionManager.setSessionDAO(sessionDAO);
.....other.....
return webSessionManager;
}
@Bean
public DefaultWebSecurityManager securityManager(SessionManager sessionManager, CacheManager cacheManager, List realms) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 注入SessionManager实例
securityManager.setSessionManager(sessionManager);
// 注入cacheManager实例
securityManager.setCacheManager(cacheManager != null ? cacheManager : new MemoryConstrainedCacheManager());
securityManager.setRealms(realms);
.....other.....
return securityManager;
}
```
3-3)SSL相关配置,提供了接口:JedisSslClientConfigurationCustomizer、LettuceClientConfigurationCustomizer、RedissonSslClientConfigurationCustomizer,可根据需要去实现定制器,并注册Bean。
示例如下:
```
@Bean
public JedisSslClientConfigurationCustomizer JedisSslClientConfigurationCustomizer() {
return ((builder) -> {
....SSL配置....
});
}
```
3-4)配置属性
| 属性项 | 缺省 | 描述 |
|-----|----|----|
|**基本配置**|
| shiro.redis.host|localhost|主机名|
| shiro.redis.port |6379|端口|
| shiro.redis.database |0 | 数据库 |
| shiro.redis.password ||密码|
| shiro.redis.sentinel.master-name ||哨兵模式中主节点名称|
| shiro.redis.sentinel.nodes ||哨兵节点地址串,逗号分隔,eg:127.0.0.1:56379,127.0.0.1:56479,127.0.0.1:56579|
| shiro.redis.cluster.max-attempts | 5 | 最大重试次数 |
| shiro.redis.cluster.nodes | | 集群节点地址串,逗号分隔,eg: 127.0.0.1:16379,127.0.0.1:16380,127.0.0.1:16381... |
|**Jedis**|
| shiro.redis.jedis.client-name ||客户端名称|
| shiro.redis.jedis.connect-timeout |2000ms|连接超时|
| shiro.redis.jedis.so-timeout |2000ms|读取超时|
| shiro.redis.jedis.ssl |false|是否启用SSL|
| shiro.redis.jedis.pool.min-idle |3||
| shiro.redis.jedis.pool.max-idle |8||
| shiro.redis.jedis.pool.max-total |8||
| shiro.redis.jedis.pool.max-wait-millis |90000||
| shiro.redis.jedis.pool.min-evictable-idle-time-millis |60000||
| shiro.redis.jedis.pool.test-on-borrow |false||
| shiro.redis.jedis.pool.test-while-idle |true||
| shiro.redis.jedis.pool.time-between-eviction-runs-millis |30000||
| shiro.redis.jedis.pool.num-tests-per-eviction-run |-1||
|**Lettuce**|
| shiro.redis.lettuce.client-name ||客户端名称|
| shiro.redis.lettuce.read-from ||读操作节点偏好|
| shiro.redis.lettuce.ssl |false|是否启用SSL|
| shiro.redis.lettuce.verify-peer |true|是否启用SSL证书校验|
| shiro.redis.lettuce.start-tls |false|是否启用StartTLS|
| shiro.redis.lettuce.pool.min-idle |3||
| shiro.redis.lettuce.pool.max-idle |8||
| shiro.redis.lettuce.pool.max-total |8||
| shiro.redis.lettuce.pool.max-wait-millis |90000||
| shiro.redis.lettuce.pool.min-evictable-idle-time-millis |60000||
| shiro.redis.lettuce.pool.test-on-borrow |false||
| shiro.redis.lettuce.pool.test-while-idle |true||
| shiro.redis.lettuce.pool.time-between-eviction-runs-millis |30000||
| shiro.redis.lettuce.pool.num-tests-per-eviction-run |-1||
|**Redisson**|
| shiro.redis.redisson.client-name ||客户端名称|
| shiro.redis.redisson.connect-timeout |10000ms|连接超时|
| shiro.redis.redisson.connection-min-idle-size |8|最少空闲连接数|
| shiro.redis.redisson.connection-pool-size |32|连接池大小|
| shiro.redis.redisson.so-timeout |3000ms|读取超时|
| shiro.redis.redisson.ssl |false|是否启用SSL|
|**Shiro缓存配置**|
| shiro.redis.cache.batch-options.delete-batch-size | 5000 | 批量删除数量 |
| shiro.redis.cache.batch-options.fetch-batch-size | 50 | 批量获取数量 |
| shiro.redis.cache.batch-options.scan-batch-size | 3000 | 每批次扫描数量 |
| shiro.redis.cache.database | 0 | shiro缓存数据库 |
| shiro.redis.cache.expiration | PT15M | shiro缓存失效时长 |
| shiro.redis.cache.key-prefix | shiro:cache: | shiro缓存键前缀 |
**4、关于缓存key的特别说明**
针对非 byte[] 和 String 类型的缓存key,采用的是生成MD5作为key的策略,这样就要求AuthorizingRealm#doGetAuthenticationInfo返回的[PrincipalCollection principals]必须是一成不变的,这样一来,如果后续需要动态修改principals的属性,则会导致缓存key的变化。
所以,建议重写这两个方法来应对这种变化:
1)AuthorizingRealm #getAuthorizationCacheKey(PrincipalCollection principals)
2)AuthorizingRealm #getAuthenticationCacheKey(PrincipalCollection principals)
eg:
```
/**
* 建议重写此方法,提供唯一的缓存Key
*/
@Override
protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
return this.getAuthenticationCacheKey(principals);
}
/**
* 建议重写此方法,提供唯一的缓存Key
*/
@SuppressWarnings("unchecked")
@Override
protected Object getAuthenticationCacheKey(PrincipalCollection principals) {
StringBuilder sb = new StringBuilder();
principals.forEach(principal -> {
sb.append(((User) principal).getId());
});
return sb.toString();
}
```
更多正在补充中。。。。。 :smile:
**Features**
欢迎提出更好的意见,帮助完善 shiro-redis
**Copyright**
Apache License, Version 2.0