个人公众号: MarkerHub,Java网站: https://markerhub.com更多精选文章请点击:Java笔记大全.mdjava
集群的分布式场景中,咱们须要把众多服务的会话状态保持一致,常见的就是把会话信息保存到redis中实现共享,那么你知道shiro集成redis实现会话共享有多简单吗?真的只须要4步!nginx
在一些分布式场景中,好比一个简单负载均衡场景,一个nginx,反向代理到两个tomcat,tomcat运行这一样的项目,那么这时候,服务的会话须要共享,由于咱们已经使用了shiro来完成咱们的认证受权逻辑,那么shiro完成登陆以后,如何让另一个服务同时也是登陆状态呢?git
咱们延用上篇文章的项目代码,使用两个端口8080、8081分别启动项目。github
有些同窗不知道怎么用idea同一个项目分别启动两个端口,其实很简单,只须要在Run/Debug Configurations
的VM options
上,指定启动端口-Dserver.port=8081
便可!web
ok,分别启动8080和8081项目以后,登陆8080项目,而后访问8081,发现8081未登陆!图示以下:redis
那么,如何才能8080登陆以后,8081也同时完成登陆呢?spring
其实在负载均衡集群中,有些人是这样解决问题,给ip指定服务,好比某个用户请求通过nginx反向代理到8080服务,那么nginx上指定ip_hash:依据ip分配方式
,那么这个用户就一直访问同一个服务,不会访问到8081服务,因此用户就一直是访问统一服务,因此在用户看来,他就一直是登陆状态的。数据库
可是,这是有缺陷的,由于ip和服务绑定了,加入这个服务挂了以后,是不会转发到其余服务,因此对这用户来讲,就访问异常。segmentfault
因此咱们须要使用更经常使用的负载均衡策略,好比轮询、权重等。缓存
ok,进入正题,shiro作会话共享,会话信息能够存储到内存,数据库,或者缓存中间件中,这里咱们使用一个经常使用的缓存中间件Redis来保存咱们的会话信息,那么,咱们就须要shiro集成redis。
能够回顾一下以前咱们介绍过的shiro的总体架构:
上面与会话或缓存相关的组件有:
若是只是作会话共享,只是改写Session DAO好像也是能够的,我以前试过,不过既然shiro已经集成redis,那么数据啥的最好也一块儿共享吧,防止出现缓存不一致的状况。按照这个逻辑,其实就是重写这3个组件就好了。
那么,有什么已经写好的shiro集成redis整合项目嘛?
这里给你们介绍一个
https://github.com/alexxiyang/shiro-redis/ # 文档 https://github.com/alexxiyang/shiro-redis/blob/master/docs/README.md # 或者 http://alexxiyang.github.io/shiro-redis/
readme.md上有详细的教程,这里咱们直接使用Spring boot starter
方式,由于须要写的代码少,直接写写配置就好。
第一步:导入shiro-redis的starter包
<dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis-spring-boot-starter</artifactId> <version>3.2.1</version> </dependency>
能够看下shiro-redis-spring-boot-starter
源码:
能够看出,已经包含了shiro-spring-boot-web-starter
与shiro-redis
整合包了,因此以前项目中整合进来的shiro-spring-boot-web-starter
能够注释掉了。
第二步,根听说明,readme里面说,若是你没有自定义建立SessionManager or SessionsSecurityManager,那么会自动给你建立,集成完成。可是咱们自定义了realm,因此SecurityManager仍是必需要自定义的。
@Configuration public class ShiroConfig { @Autowired RedisSessionDAO redisSessionDAO; @Autowired RedisCacheManager redisCacheManager; @Bean AccountRealm accountRealm() { return new AccountRealm(); } @Bean public SessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); // inject redisSessionDAO sessionManager.setSessionDAO(redisSessionDAO); return sessionManager; } @Bean public DefaultWebSecurityManager securityManager(AccountRealm accountRealm, SessionManager sessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(accountRealm); //inject sessionManager securityManager.setSessionManager(sessionManager); // inject redisCacheManager securityManager.setCacheManager(redisCacheManager); return securityManager; } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); // logged in users with the 'admin' role chainDefinition.addPathDefinition("/admin/**", "authc, roles[admin]"); // logged in users with the 'document:read' permission chainDefinition.addPathDefinition("/docs/**", "authc, perms[document:read]"); chainDefinition.addPathDefinition("/login", "anon"); chainDefinition.addPathDefinition("/doLogin", "anon"); // all other paths require a logged in user chainDefinition.addPathDefinition("/**", "authc"); return chainDefinition; } }
相比以前的配置,多了配置了个SessionManager,而后对应配置中注入sessionManager和redisCacheManager。好像项目就已经能够运行啦。
登陆成功以后查看redis中的数据效果以下:
说明咱们的会话信息已经保存到redis中啦。而后咱们再换个端口8081启动项目,发现8080登陆成功以后,8081服务也是登陆成功状态。
第三步、根据需求调整参数,能够在配置文件中调整的参数我贴出来:
shiro-redis: enabled: true redis-manager: host: 127.0.0.1:6379
ok,shiro-redis已经整合完毕,是否是挺简单的哈。
使用这个整合包,有个注意点,若是你使用了spring-boot-devtools做为自动热加载重启,那么自动重启后会报错,解决方法也简单,官方已经给出了解决方案:
If you are using shiro-redis with spring-boot-devtools. Please add this line to resources/META-INF/spring-devtools.properties (Create it if there is no this file):restart.include.shiro-redis=/shiro-[\w-\.]+jar
因此,第四步:只须要在resources新建一个文件夹META-INF,而后新建文件spring-devtools.properties,内容为:
restart.include.shiro-redis=/shiro-[\\w-\\.]+jar
效果以下:
好了,今天先讲到这里吧,shiro系列的文章已经发了几篇了,后面还有一篇集成单点登陆的,而后就完结了哈。这里是MarkerHub,我是小Hub吕一明,快去星标置顶个人公众号吧!
(完)