Shiro结合Redis实现分布式或集群环境下的Session共享

本篇是Shiro系列第二篇,使用Shiro基于Redis实现分布式或集群环境下的Session共享。在讲Session共享之前先说一下为什么要做Session共享。

什么是Session

我们都知道HTTP协议(1.1)是无状态的,所以服务器在需要识别用户访问的时候,就要做相应的记录用于跟踪用户操作,这个实现机制就是Session。当一个用户第一次访问服务器的时候,服务器就会为用户创建一个Session,每个Session都有一个唯一的SessionId(应用级别)用于标识用户。

Session通常不会单独出现,因为请求是无状态的,那么我们必须让用户在下次请求时带上服务器为其生成的Session的ID,通常的做法时使用Cookie实现(当然你要非要在请求参数中带上SessionId那也不是不行)。请求返回时会向浏览器的Cookie中写入SessionID,通常使用的键是 JSESSIONID,这样下次用户再请求这台服务器时,服务器就能从Cookie中取出SessionId识别出该次请求的用户是谁。

举个栗子:

左边红框部分是Cookie列表,当前服务器是:localhost:28080。右边红框部分从左到右依次是Cookie的键、值、主机、路径和过期时间。路径为 /时表示全站有效,最后一个过期时间未设置的话是默认值为Session,表示浏览器关闭时该Cookie失效。我们也可以为Cookie指定过期时间,以做到会话保持。

什么是Session共享

通过Session和Cookie,我们使得无状态的HTTP协议间接的变成了有状态的了,可以实现保持登录,存储用户信息,购物车等等功能。但是随着服务访问人数的增多,单台服务器已经不足以应付所有的请求了,必须部署集群环境。但是随着集群环境的出现,追踪用户状态的问题又开始出现问题,之前用户在A服务器登录,A服务器保存了用户信息,但是下一次请求发送到B服务器去了,这时候B服务器是不知道用户在A服务器登录的事情的,它虽然也能拿到用户请求Cookie中的SessionId,但是在B服务根据这个SessionId找不到对应的Session,B服务器就会认为用户没有登录,需要用户重新登录,这对用户来说是没办法接受的。

这时候常见的有两种方式解决这个问题,第一种是让这个用户所有的请求都发送到A服务器,比如根据IP地址做一些列算法将所有用户分配到不同的服务器上去,让每个用户只访问其中的一台服务器。这种做法可行,但是后续也会产生其它问题,更好的做法是第二种,将所有的服务器上的Session都做成共享的,A服务能拿到B服务器上的所有Session,同理B服务器也能获取A服务器所有的Session,这样上面的问题就不存在了。

上一篇已经通过Shiro实现了用户登录和权限管理,Shiro的登录也是基于Session的,默认情况下Session是保存在内存中。既然要做Session共享,那么肯定是将Session抽取出来,放到一个多个服务器都能访问到的地方。

在集群环境下,我们仅仅需要继承AbstractSessionDAO,实现一下Session的增删改查等几个方法就可以很方便的实现Session共享,Shiro已经将完整的流程都做好了。这里涉及到的设计模式是模板方法模式,我们仅需要参与部分业务就可以完善整个流程了,当然我们不参与这部分流程的话,Shiro也有默认的实现方式,那就是将Session管理在当前应用的内存中。

具体的Session管理(共享)怎么实现由我们自己决定,可以存放在数据库,也可以通过网络传输,甚至可以通过IO流写入文件都行,但就性能来讲,我们一般都将Session放入Redis中。Redis大法好!YES~

自定义RedisSessionDAO

理解了原理之后就很容易办事了,继承AbstractSessionDAO后实现Session增删改查的几个方法,然后再分布式系统中所有的项目再需要存储或获取Session时都会走Redis操作,这样就做到了集群环境的Session共享了。代码非常简单:

配置文件中添加上面用到的配置

###redis连接配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=foobared
### Session过期时间(秒)
session.redis.expireTime=3600

注入RedisSessionDao

上面只是我们自己实现的管理Session的方式,现在需要将其注入SessionManager中,并设置过期时间等相关参数。

再将SessionManager注入Shiro的安全管理器SecurityManager中,前面说过,我们围绕安全相关的所有操作,都需要与SecurityManager打交道,这位才是Shiro中真正的老大哥。

OK,至此基于Redis实现的Session共享就完成了,是不是简单得不可思议。

注意:基于网络传输的对象请实现Serializable序列化接口,比如User类。

将这套代码用不同的端口跑两套服务(理论上跑多少套都可以只要你的配置够用),访问两台服务器获取用户信息的接口,未登录状态毫无疑问都会跳到登录页去:

在任意一台服务器上调用登录接口登录:

登录成功后再次分别访问两台服务器获取用户信息的接口:

如此,分布式环境Session共享完美实现。最后继续放上项目代码,代码还是很早之前的,部分代码为了配合此篇笔记经过修改整理后上传。

本篇结束,简直不要太简单是不是,其实这主要是因为大部分工作Shiro都帮我们做了,细节的东西都被Shiro隐藏起来,我们仅仅需要添加一些简单的配置就可以实现强大的功能,这就是框架的好处。

但是作为一个程序员,仅仅调用一个方法或者添加一个注解就实现了一套很强大的功能,而我们却看不到一个if判断和for循环的时候心里应该是非常不踏实的。我们不仅要学会使用框架,更要去深入理解框架,至少要知道为什么我们就加了一个注解框架就能帮我们实现一大堆功能,只有这样才能让我们感到脚踏实地。下一篇,深入Shiro源码看看,可能需要酝酿一下想想笔记怎么写。

Original: https://www.cnblogs.com/zhuawang/p/13545413.html
Author: 上校
Title: Shiro结合Redis实现分布式或集群环境下的Session共享

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/528958/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 外键,查询关键字

    目录 自增特性 约束条件之外键 *查询关键字 内容 自增特性 自增不会随着数据的删除而回退 删除数据但无法重置主键 truncate 删除数据并重置主键值 约束条件之外键 简介 给…

    Linux 2023年6月7日
    093
  • aspx.designer.cs没有自动生成代码(没有自动注册)

    遇到这个问题的最大可能是:aspx页面存在bug。 比如说我的主页是从项目里的别的页面复制过来的,但是少复制了一些引用,页面就存在bug,导致aspx.designer.cs没有自…

    Linux 2023年6月7日
    083
  • django Middleware

    Middleware简介 Middleware是一个轻量级的,全局性质的Django请求/响应处理钩子框架。所谓钩子框架是指在request请求到达Django之后,views视图…

    Linux 2023年6月7日
    0104
  • Kubernetes后台数据库etcd:安装部署etcd集群,数据备份与恢复

    服务器版本 docker软件版本 CPU架构 CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 x86_64…

    Linux 2023年6月7日
    089
  • 基于libevent的http服务器实现

    基于libevent的http服务器实现 //libevent的http服务器简单实现方式 #include #include #include #include //for st…

    Linux 2023年6月14日
    0107
  • 学生管理系统(初级)

    #include #include #include #define Size sizeof(struct Student) struct Student *p = NULL; t…

    Linux 2023年6月7日
    0101
  • Guava中的封装的Map操作

    引入依赖 <dependency> <groupId>com.google.guavagroupId> <artifactId>guava…

    Linux 2023年6月7日
    0108
  • php微信自定义分享链接,标题,描述,缩略图配置步骤

    微信公众号开发,自定义分享链接,标题,描述,缩略图接口 1、文件目录结构 2、后台代码: wxshare.php 注意:使用此代码,只需要把wxshare.php文件下面的appi…

    Linux 2023年6月7日
    092
  • Redis 缓存穿透、雪崩、击穿以及相关解决方案

    缓存流程: 缓存穿透: 什么是缓存穿透:是指 redis 和数据库都没有这个数据,大量请求该数据造成数据库挂掉,该请求一般是非正常用户 解决方案: 布隆过滤器:将数据库中所有的查询…

    Linux 2023年5月28日
    079
  • 天气干燥怎么防止被静电电到

    可以摸一下墙壁或地板,把电放掉,这样摸门把手之类的金属物品就不会被电到了。 可以摸一下墙壁或地板,把电放掉,这样摸门把手之类的金属物品就不会被电到了。亲身实践,十分有效。只是摸墙和…

    Linux 2023年6月6日
    094
  • Optional 常用方法总结

    转载请注明出处: Optional 类是 JAVA 8 提供的判断程序是否为空提供的包装工具类;可以减少代码中的 是否为空的判断,以及减少 NullPointerException…

    Linux 2023年6月14日
    0118
  • SQL44 将id=5以及emp_no=10001的行数据替换成id=5以及emp_no=10005

    本题链接表结构如下所示。 +—-+——–+—————–+————+————+ | id | emp_no | t…

    Linux 2023年6月13日
    0101
  • Laxcus远程终端

    Laxcus集群操作系统的远程终端越来越象Linux的VIM了,除了界面风格之外,在用户使用的命令上也在向VIM靠近,原因嘛也不难理解,毕竟Laxcus是一个分布式的操作系统,处理…

    Linux 2023年6月6日
    0112
  • OpenStack cinder对接glusterfs存储

    一、创建虚拟机node1 自定义默认下一步稍后安装操作系统选择Linux,红帽6名称位置随意1核就行2G内存就行仅主机网络默认下一步默认下一步默认下一步30G,给单个文件添加一块5…

    Linux 2023年6月8日
    093
  • CPU 是如何与内存交互的

    这篇文章主要整理了一下计算机中的内存结构,以及 CPU 是如何读写内存中的数据的,如何维护 CPU 缓存中的数据一致性。什么是虚拟内存,以及它存在的必要性。如有不对请多多指教。 概…

    Linux 2023年6月8日
    092
  • docker 安装mysql5.7

    docker 安装mysql5.7 前言 MySQL 是目前最流行的关系型数据库管理系统,开发者是瑞典MySQL AB公司。目前MySQL被广泛地应用在Internet上的中小型网…

    Linux 2023年6月6日
    096
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球