SpringBoot 2.x 开发案例之 Shiro 整合 Redis

前言
前段时间做了一个图床的小项目,安全框架使用的是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;
}
}
小结
是不是很爽,以后重启应用再也不用担心用户投诉了?
最后,推荐下小黄图:https://www.cloudbed.vip
SpringBoot 2.x 开发案例之 Shiro 整合 Redis的更多相关文章
- SpringBoot 2.x (10):整合Redis
Redis部署到阿里云: 下载redis源码,编译,允许远程访问的配置 阿里云安全组设置: SSH连过去: wget http://download.redis.io/releases/redis-4 ...
- SpringBoot 2.x 开发案例之前后端分离鉴权
前言 阅读本文需要一定的前后端开发基础,前后端分离已成为互联网项目开发的业界标准使用方式,通过Nginx代理+Tomcat的方式有效的进行解耦,并且前后端分离会为以后的大型分布式架构.弹性计算架构.微 ...
- SpringBoot:Shiro 整合 Redis
前言 前段时间做了一个图床的小项目,安全框架使用的是Shiro.为了使用户7x24小时访问,决定把项目由单机升级为集群部署架构.但是安全框架shiro只有单机存储的SessionDao,尽管Shrio ...
- SpringBoot 2.0 开发案例之百倍级减肥瘦身之旅
前言 为了存我的小黄图,最近在做一款图床服务,集成了各种第三方云存储服务,目前正在内部测试阶段.项目是以Jar的形式运行在腾讯云上,不要问我为什么使用腾讯云了,因为阿里云老用户和狗不得入内. 问题凸显 ...
- 展开被 SpringBoot 玩的日子 《 三 》 整合Redis
SpringBoot对常用的数据库支持外,对NoSQL 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结构 ...
- Shiro整合springboot,freemaker,redis(含权限系统完整源码)
区块链技术联盟 2018-02-08 17:06:40 目录 一.导语 二.shiro功能介绍 三.shiro详解 四.shiro实战案例分享 五.系统配置 六.其他 一.导语 今天推荐给大家一个非常 ...
- SpringBoot开发案例从0到1构建分布式秒杀系统
前言 最近,被推送了不少秒杀架构的文章,忙里偷闲自己也总结了一下互联网平台秒杀架构设计,当然也借鉴了不少同学的思路.俗话说,脱离案例讲架构都是耍流氓,最终使用SpringBoot模拟实现了部分秒杀场 ...
- SpringBoot开发案例之多任务并行+线程池处理
前言 前几篇文章着重介绍了后端服务数据库和多线程并行处理优化,并示例了改造前后的伪代码逻辑.当然了,优化是无止境的,前人栽树后人乘凉.作为我们开发者来说,既然站在了巨人的肩膀上,就要写出更加优化的程序 ...
- springboot 与 shiro 整合 (简洁版)
前言: 网上有很多springboot 与 shiro 整合的资料,有些确实写得很好, 对学习shiro和springboot 都有很大的帮助. 有些朋友比较省事, 直接转发或者复制粘贴.但是没有经过 ...
随机推荐
- vue+file-saver+xlsx导出table表格为excel
https://blog.csdn.net/wjswangjinsheng/article/details/91393396
- 以P2P网贷为例互联网金融产品如何利用大数据做风控?
以P2P网贷为例互联网金融产品如何利用大数据做风控? 销售环节 了解客户申请意愿和申请信息的真实性:适用于信贷员模式. 风控关键点 亲见申请人,亲见申请人证件,亲见申请人签字,亲见申请人单位. 审 ...
- codeforces 616D
题意:给你n个数,找出一个最大的区间,满足:不同的数值个数不超过k; //我开始又看错题了. 以为是找出一个最大区间,里面的数的最大值不超过k; 思路:利用一个窗口滑动,左端点表示当前位置,右端点表示 ...
- 使用jackson转json解决双向关联循环调用
ITOO V1.0的开发算是告一段落了,现在是整理总结交接环节,在这个项目中常见的问题也该好好整理一下和大家分享了,这次主要介绍转json循环调用的问题. 一.问题背景 相信只要使用ORM映射实体关联 ...
- laravel构造函数和中间件执行顺序问题
今天想重构下代码结构: BaseController.php 放置公共的中间件 class BaseController { public function __construct(){ $this- ...
- 关于scipy包的安装
先安装好scikit-learn和numpy,从网上下载scipy的whl文件,通过pip install+安装包地址的方法安装
- 2019-1-29-WPF-设置输入只能英文
title author date CreateTime categories WPF 设置输入只能英文 lindexi 2019-1-29 15:8:4 +0800 2018-2-13 17:23: ...
- java 使用反射调用可变参数方法
使用反射操作对象-调用可变参数方法 要把可变参数都当做是其对应的数组类型参数; 如 show(XX... is)作为show(XX[] is)调用; 若可变参数元素类型是引用类型: JDK内部接收到参 ...
- es6笔记 day1---let和const的应用
ES6 -> ECMA标准 ES7 ES8 最早是由ECMA-262版本实现的 ---------------------------------------- ES6 也称为ES2015,2 ...
- Team Foundation Server 2015使用教程【6】:新增权限为读取器的团队