前言
上一篇博客采用了搭建Demo的方式说明了如何使用Shiro完成最基础的“登录/登出”和“权限鉴别”功能。而本篇博客将介绍Shiro与Redis结合,加入“缓存权限”和“共享Session”功能。本Demo仍然力求简洁清晰,因此在工程代码中有与上一篇博客代码重合部分将被省略,如有不清楚的地方请先看上一篇博客然后再回来继续阅读。
业务设计
(1) 缓存权限:自定义realm继承了AuthorizingRealm,实际上每调用一个需要权限验证的接口,都会执行doGetAuthorizationInfo方法,从数据库中查出用户权限、角色等信息,在demo测试中这种方式完全没有问题但在生产环境则是不可行的,设想一下明明一次就能查出的数据,成百上千的用户每访问一个接口就要查一遍数据权限,这是对资源的极大浪费而且还会给服务器代来额外的压力,针对这个问题幸好Shiro为我们提供了缓存权限的扩展来专门解决。本Demo使用Redis来作为Shiro的缓存,当第一次调用权限验证时程序执行doGetAuthorizationInfo查询数据并装载到Redis缓存中,此后再访问权限验证接口时Shiro会直接在缓存中查找权限提高效率,另外,当用户登出系统时程序会自动清除缓存的权限,以保证用户的使用安全。
(2)共享Session:在部署生成环境时为了提高程序的可用性,往往都会采取HA(高可用)方式进行部署,如使用Nginx作为反向代理后接A、B两个Tomcat时,如何共享Session共就成了问题,当然此问题有很多解决办法,但本文所要介绍的是采用Redis来存储Session的方式对外共享Session。原理如图所示:
更新工程
在原工程基础上增加Redis 缓存和共享Session支持,只需要将Redis集成进工程然后修改Shiro配置类增加Redis相关配置,通过这样简单两步即可完成。
(1)集成Redis
pom.xml
<!-- 添加redis 缓存-->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>2.4.2.1-RELEASE</version>
</dependency>
<!-- 添加redis连接工具-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
application.yml
jedis:
pool:
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 0
# 连接池最大连接数(使用负值表示没有限制)
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
timeout: 0
(2)修改Shiro配置类
ShiroConfig
/**
* 权限管理,配置主要是Realm的管理认证
* @return
*/
@Bean
public SecurityManager securityManager(RedisCacheManager cacheManager
,DefaultWebSessionManager redisSessionManager) {
......
securityManager.setCacheManager(cacheManager); // 配置Redis 缓存
securityManager.setSessionManager(redisSessionManager); // 配置Redis Session
......
}
/**
* 创建RedisManager
* @return
*/
@Bean
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setExpire(1800);// 配置缓存过期时间
return redisManager;
}
/**
* 配置Rides缓存
* @param redisManager
* @return
*/
@Bean
public RedisCacheManager cacheManager(RedisManager redisManager) {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager);
return redisCacheManager;
}
/**
* 配置RedisSessionManager
* @param redisSessionDAO
* @return
*/
@Bean
public DefaultWebSessionManager redisSessionManager(RedisSessionDAO redisSessionDAO) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO);
return sessionManager;
}
/**
* 配置RidesSessionDao
* @param redisManager
* @return
*/
@Bean
public RedisSessionDAO redisSessionDAO(RedisManager redisManager) {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager);
return redisSessionDAO;
}
可以看一下,在redis中的缓存情况,发现已经写入一切正常