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 都有很大的帮助. 有些朋友比较省事, 直接转发或者复制粘贴.但是没有经过 ...
随机推荐
- 使用java实现CNN的实战
使用java实现CNN的实战 1.要实现CNN,其中包括 卷积.池化(下采样).分类器.优化方法.分类器.反向传播 2.可以使用一个三维数组来表示一张图片(通道.行.列) 3.卷积,卷积的方式有三种: ...
- spark mllib docs,MLlib: RDD-based API
MLlib: RDD-based API This page documents sections of the MLlib guide for the RDD-based API (the spar ...
- jackson中的@JsonBackReference和@JsonManagedReference,以及@JsonIgnore
jackson中的@JsonBackReference和@JsonManagedReference,以及@JsonIgnore均是为了解决对象中存在双向引用导致的无限递归(infinite recur ...
- 日历价差(calendar spread)
日历价差(calendar spread) 是指投资者买进到期日较远的期权 (简称远期期权),同时又卖出相同行权价格.相同数量但到期日较近的期权(简称近期期权),赚取两个不同期权隐含波动率的差价或者其 ...
- hadoop-1.2.1 伪分布配置
首先JDK安装及相关环境变量配置 # Java environment setting JAVA_HOME=/usr/java/default CLASSPATH=.:$JAVA_HOME/lib/t ...
- H3C 最大跳数16导致网络尺度小
- vue项目上滑滚动加载更多&下拉刷新
上滑滚动时获取内容高度.屏幕高度和滚动高度(此处#sslist要为内容是id) 内容高度 let innerHeight = document.querySelector("#sslist ...
- 20191029校内ACM部分题解
20191029校内ACM部分题解 https://codeforces.com/group/32W4q7bPme/contest/257710 B数学 给定一个在\([0,1]\)等概率随机区间的随 ...
- C# 大端小端转换
关于大端和小端,是一个有趣的问题.本文告诉大家如何在C#转换大端和小端. 这里有一个有趣的故事,请看详解大端模式和小端模式 - CSDN博客 默认的 C# 使用的是小端,如果收到的消息是大端,那么就会 ...
- Linux 内核硬件抽象
我们结束 PCI 的讨论, 通过快速看一下系统如何处理在市场上的多种 PCI 控制器. 这只 是一个信息性的小节, 打算来展示给好奇的读者, 内核的面向对象分布如何向下扩展到最 低层. 用来实现硬件抽 ...