SpringBoot 2.x 开发案例之 Shiro 整合 Redis
程序员文章站
2022-06-05 17:00:41
前言 前段时间做了一个图床的小项目,安全框架使用的是 。为了使用户 小时访问,决定把项目由单机升级为集群部署架构。但是安全框架 只有单机存储的 ,尽管 有基于 的组播/广播实现,然而集群的分布往往是跨网段的,甚至是跨地域的,所以寻求新的方案。 架构 方案 使用 集中存储,实现分布式集群共享用户信息, ......
前言
前段时间做了一个图床的小项目,安全框架使用的是shiro
。为了使用户7x24
小时访问,决定把项目由单机升级为集群部署架构。但是安全框架shiro
只有单机存储的sessiondao
,尽管shrio
有基于ehcache-rmi
的组播/广播实现,然而集群的分布往往是跨网段的,甚至是跨地域的,所以寻求新的方案。
架构
方案
使用 redis
集中存储,实现分布式集群共享用户信息,这里我们采用第三方开源插件crazycake
来实现,pom.xml
引入:
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-redis</artifactid> </dependency> <dependency> <groupid>org.crazycake</groupid> <artifactid>shiro-redis</artifactid> <version>3.2.3</version> </dependency>
配置 application.properties
:
# redis # 数据库索引(默认为0) redis.database=0 # 服务器地址 变更为自己的 redis.host=127.0.0.1 # 服务器连接端口 redis.port=6379 # 服务器连接密码,如果不设置密码注释掉即可 # redis.password= # 连接超时时间(毫秒) redis.timeout=30000
本来crazycake
插件已经实现了redismanager
,但是参数不可配,这里我们需要自己重写一下:
/** * 重写 redismanager * 博客:https://blog.52itstyle.vip */ public class redismanager extends workaloneredismanager implements iredismanager { private redisproperties redis; private jedispool jedispool; public redismanager(redisproperties redis) { this.redis = redis; } private void init() { synchronized(this) { if (this.jedispool == null) { this.jedispool = new jedispool(this.getjedispoolconfig(), redis.gethost(), redis.getport(), redis.gettimeout(), redis.getpassword(), redis.getdatabase()); } } } @override protected jedis getjedis() { if (this.jedispool == null) { this.init(); } return this.jedispool.getresource(); } }
参数配置 redisproperties
:
@data @configurationproperties(prefix = "redis") public class redisproperties { private string host; private int port; private int timeout; private string password; private int database; }
配置 shiroconfig
:
/** * shiro权限配置 * 一定要配置 @configuration 和 @enableconfigurationproperties 注解 * 博客:https://blog.52itstyle.vip */ @configuration @enableconfigurationproperties({redisproperties.class}) public class shiroconfig { private redisproperties redis; public shiroconfig(redisproperties redis) { this.redis = redis; } @bean public userrealm userrealm() { return new userrealm(); } @bean public shirofilterfactorybean shirofilterfactorybean (securitymanager securitymanager) { shirofilterfactorybean shirofilterfactorybean = new shirofilterfactorybean(); shirofilterfactorybean.setsecuritymanager(securitymanager); shirofilterfactorybean.setloginurl("/index.html"); shirofilterfactorybean.setunauthorizedurl("/403"); // 拦截器 map<string, string> filterchaindefinitionmap = new linkedhashmap<>(); /** * 静态文件 */ filterchaindefinitionmap.put("/file/**","anon"); /** * 登录注册 */ filterchaindefinitionmap.put("/register.shtml","anon"); filterchaindefinitionmap.put("/login.shtml","anon"); /** * 管理后台 */ filterchaindefinitionmap.put("/sys/**", "roles[admin]"); filterchaindefinitionmap.put("/**", "authc"); shirofilterfactorybean.setfilterchaindefinitionmap(filterchaindefinitionmap); return shirofilterfactorybean; } @bean public sessionssecuritymanager securitymanager() { defaultwebsecuritymanager securitymanager = new defaultwebsecuritymanager(); securitymanager.setrealm(userrealm()); securitymanager.setcachemanager(cachemanager()); securitymanager.setsessionmanager(sessionmanager()); return securitymanager; } @bean public defaultwebsessionmanager sessionmanager() { defaultwebsessionmanager sessionmanager = new defaultwebsessionmanager(); sessionmanager.setsessionidurlrewritingenabled(false); sessionmanager.setsessiondao(redissessiondao()); return sessionmanager; } @bean public shirodialect shirodialect(){ return new shirodialect(); } /** * cachemanager 缓存 redis实现 * @return */ public rediscachemanager cachemanager() { rediscachemanager rediscachemanager = new rediscachemanager(); rediscachemanager.setredismanager(redismanager()); return rediscachemanager; } /** * 配置shiro redismanager * @return */ public redismanager redismanager() { redismanager redismanager = new redismanager(redis); return redismanager; } /** * redissessiondao shiro sessiondao层的实现 * 原理就是重写 abstractsessiondao * 有兴趣的小伙伴自行阅读源码 */ @bean public redissessiondao redissessiondao() { redissessiondao redissessiondao = new redissessiondao(); redissessiondao.setredismanager(redismanager()); return redissessiondao; } }
小结
是不是很爽,以后重启应用再也不用担心用户投诉了?
最后,推荐下小黄图: