前言

前段时间做了一个图床的小项目,安全框架使用的是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的更多相关文章

  1. SpringBoot 2.x (10):整合Redis

    Redis部署到阿里云: 下载redis源码,编译,允许远程访问的配置 阿里云安全组设置: SSH连过去: wget http://download.redis.io/releases/redis-4 ...

  2. SpringBoot 2.x 开发案例之前后端分离鉴权

    前言 阅读本文需要一定的前后端开发基础,前后端分离已成为互联网项目开发的业界标准使用方式,通过Nginx代理+Tomcat的方式有效的进行解耦,并且前后端分离会为以后的大型分布式架构.弹性计算架构.微 ...

  3. SpringBoot:Shiro 整合 Redis

    前言 前段时间做了一个图床的小项目,安全框架使用的是Shiro.为了使用户7x24小时访问,决定把项目由单机升级为集群部署架构.但是安全框架shiro只有单机存储的SessionDao,尽管Shrio ...

  4. SpringBoot 2.0 开发案例之百倍级减肥瘦身之旅

    前言 为了存我的小黄图,最近在做一款图床服务,集成了各种第三方云存储服务,目前正在内部测试阶段.项目是以Jar的形式运行在腾讯云上,不要问我为什么使用腾讯云了,因为阿里云老用户和狗不得入内. 问题凸显 ...

  5. 展开被 SpringBoot 玩的日子 《 三 》 整合Redis

    SpringBoot对常用的数据库支持外,对NoSQL 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结构 ...

  6. Shiro整合springboot,freemaker,redis(含权限系统完整源码)

    区块链技术联盟 2018-02-08 17:06:40 目录 一.导语 二.shiro功能介绍 三.shiro详解 四.shiro实战案例分享 五.系统配置 六.其他 一.导语 今天推荐给大家一个非常 ...

  7. SpringBoot开发案例从0到1构建分布式秒杀系统

    前言 ​最近,被推送了不少秒杀架构的文章,忙里偷闲自己也总结了一下互联网平台秒杀架构设计,当然也借鉴了不少同学的思路.俗话说,脱离案例讲架构都是耍流氓,最终使用SpringBoot模拟实现了部分秒杀场 ...

  8. SpringBoot开发案例之多任务并行+线程池处理

    前言 前几篇文章着重介绍了后端服务数据库和多线程并行处理优化,并示例了改造前后的伪代码逻辑.当然了,优化是无止境的,前人栽树后人乘凉.作为我们开发者来说,既然站在了巨人的肩膀上,就要写出更加优化的程序 ...

  9. springboot 与 shiro 整合 (简洁版)

    前言: 网上有很多springboot 与 shiro 整合的资料,有些确实写得很好, 对学习shiro和springboot 都有很大的帮助. 有些朋友比较省事, 直接转发或者复制粘贴.但是没有经过 ...

随机推荐

  1. H3C LMI

  2. 网易大数据平台的Spark技术实践

    网易大数据平台的Spark技术实践 作者 王健宗 网易的实时计算需求 对于大多数的大数据而言,实时性是其所应具备的重要属性,信息的到达和获取应满足实时性的要求,而信息的价值需在其到达那刻展现才能利益最 ...

  3. JPA 一对多双向映射 结果对象相互迭代 造成堆栈溢出问题方法

    问题: JPA 在双向映射时,会相互包含对方的实例,相互引用,造成递归迭代,堆栈溢出(java.lang.StackOverflowError). 分析: 在后端向前端传递的时候会将数据序列化,转为j ...

  4. 2019-8-31-AutoHotKey-用打码的快捷键

    title author date CreateTime categories AutoHotKey 用打码的快捷键 lindexi 2019-08-31 16:55:58 +0800 2019-06 ...

  5. 2019-4-6-VisualStudio-2019-如何离线下载

    title author date CreateTime categories VisualStudio 2019 如何离线下载 lindexi 2019-04-06 09:26:11 +0800 2 ...

  6. Python3内置函数、各数据类型(int/str/list/dict/set/tuple)的内置方法快速一览表

    Python3内置函数 https://www.runoob.com/python3/python3-built-in-functions.html int https://www.runoob.co ...

  7. Java虚拟机参数,增加虚拟机最大内存,在/etc/profile增加如下: export JAVA_OPTS="-Xms9g -Xmx9g"

    一.运行class文件 执行带main方法的class文件,Java虚拟机命令参数行为: java <CLASS文件名> 注意:CLASS文件名不要带文件后缀.class 例如: java ...

  8. vue-learning:2 - template - directive

    指令 directive 在上一节我们知道,VUE的template模板通过VUE指令API实现与页面的视图层联系.所以本节将聚集在实现视图层交互的VUE指令系统directive的基础使用. 我们先 ...

  9. 2018-4-12-win10-uwp-使用油墨输入

    title author date CreateTime categories win10 uwp 使用油墨输入 lindexi 2018-04-12 14:19:58 +0800 2018-2-13 ...

  10. [微信跳转浏览器]微信跳转外部浏览器下载APP源码,可以实现自动跳转外部浏览器打开链接

    基于微信后端开发了一款微信推广助手,使用了本程序生成的链接,用户在微信任意环境下点击链接或者扫描二维码,可以实现直接跳转手机默认浏览器并打开指定网页. 我们开发的此款跳转产品,应用范围广泛.除了下载A ...