Redis 实现分布式Session 登录相关细节

Redis 实现分布式Session 登录

借助 Redis 对 Session 信息进行统一的存储和管理,这样无论请求发送到哪台服务器,服务器都会去同一个 Redis 获取相关的 Session 信息,这样就解决了分布式系统下 Session 存储的问题。

  1. 【发送短信】校验手机号,如果校验手机号格式正确,那么就生成一个六位随机数字验证码,然后把这个六位数保存到 Redis 中,key 设置为业务前缀+手机号,value 就是 String 类型的随机数验证码,设定验证码的有效时间(2-3 分钟)防止这个 redis 中的数据越存越多。最后将验证码返回给前端。
  2. 【登录和注册】接下来用户输入手机号和验证码登录。登录时先校验手机号格式,校验格式通过后,之后根据前端发来的手机号(手机号就是 redis 中的 key 的一部分)从 redis 中获取验证码。
    a. 如果验证码一致(redis 保存的和用户输入的一致),那么就根据手机号去数据库查找用户是否存在。
    ⅰ. 如果数据库中有该用户,保存用户信息到 redis(便于后面逻辑的判断 比如登录判断、随时取用户信息,减少对数据库的查询)
    1. 随机生成一个 token(使用 UUID+一些业务前缀) 作为登录令牌,作为 redis 中的 key。
    2. 存储用户信息。【putall 方法】参数: key=token, Map(哈希表)。即以 Hash 存储到 redis
    3. 存储的时候也不能一直存一直存,需要设计用户信息的有效期,一段时间后就清除内存。
    4. 将这个 token 返回给客户端存储,以后每次发送请求的时候客户端就会携带。
      ⅱ. 如果数据库中没有该用户,那就创建新用户(补充一些用户名昵称之类的),保存到用户数据库,之后保存用户信息到 redis。
      b. 如果验证码不一致,返回失败,需要重新提交验证码手机号。
  3. 相当于之后用户的登录凭证就是 redis 中的 key(token) ,登录之后浏览器每次发送请求时,请求头就会携带含有 token 的 Cookie。那么服务端收到之后就可以通过 token 得到 redis 中存储的 value,如果得到了 value 就可以判断为登陆成功。
  4. 【后续请求时校验登录状态】后续的请求都会携带 cookie:token,通过 interceptor1 拦截器 1 拦截所有请求,之后获取 token,从而获取 redis 中的用户信息。如果成功获取到了,那么就将用户信息保存到 TreadLocal 中,然后刷新 token 有效期,之后放行。如果没有获取到用户信息,那么就直接放行(交给第二个拦截器处理)。
    之后通过 interceptor2 拦截器 2 拦截需要登录的路径,如果从 TreadLocal 中查询到用户,那么就放行,如果没查到,那么就拦截。那些不需要登录就能访问的东西,就不会被拦截了。

采用 Redis 里面的 Hash 数据结构存储:

● 对象的 String 数据结构是以 JSON 字符串的形式保存,更加直观,操作也更加简单,但是 JSON 结构会有很多非必须的内存开销,比如双引号、大括号,内存占用比 Hash 更高

● Hash 数据结构是以 Hash 表,也就是 hashkey-value 的形式保存,可以对单个字段进行CRUD更加灵活

为什么已经存在 redis 中了还需要存到 treadlocal?

  1. 减少服务器的交互,提升性能,
  2. 方便后续逻辑处理,比如:方便获取和使用用户信息,Redis获取用户信息是具有侵入性的

视频软件如何维护登录状态?

那就直接设计一个过期时间很久的 jwt,或者返回的时候制定 cookie 过期时间(这样 cookie 就会存在磁盘中,关闭浏览器也不会失去 cookie)。

JWT 如何设置过期时间?

JWTS 工具类里面setExpiration 设置。还需设置 header 中的签名算法,签名密钥。设置有效载荷 claims 等

session+cookies是基于web的,移动端用不了 cookie,所以移动端一些 api 用 jwt,开发 web 应用的话都可以。

会话:

在 web 开发中,浏览器和服务器之间的一次连接就称之为会话。只要浏览器和服务器不断开连接,那么就是属于一个会话。那么如果一个浏览器在未关闭之前请求了多次服务器,那么这些请求属于同一个回话。

会话跟踪:

就是一种维护浏览器状态的方法。我们后端服务器需要识别多次请求是否来自于同一个浏览器,从而实现在多次请求之间共享数据。从而解决 HTTP 协议是无状态的协议的问题,去辨别多次请求是否属于同一个会话,从而在一次会话的多次请求之间共享数据。

比如第一次请求登录接口,顺利通过登录校验完成之后,我们就可以设置一个cookie【HttpServletResponse 的 addCookie 方法】在 cookie 当中我们可以来存储用户相关的一些数据信息。比如我可以在 cookie 当中来存储当前登录用户的用户名,用户的ID 等等。

服务器端在给客户端响应数据的时候,会将 cookie 响应给浏览器(放在响应头 Set-Cookie 中),浏览器接收到响应回来的 cookie 之后,会自动的将 cookie 的值存储在浏览器本地。接下来在后续的每一次请求当中,都会将浏览器本地所存储的 cookie 自动地携带到服务端(放在请求头 Cookie 中)。

接下来在服务端我们就可以去获取 cookie 。【HttpServletResponse 的 getCookie 方法】判断这个 cookie 中的值是否存在,如果不存在这个cookie,就说明客户端之前是没有访问登录接口的,那后续的页面也就不能被访问,只能让他访问登录界面;如果存在 cookie 的值,就说明客户端之前已经登录完成了。这样我们就可以基于 cookie 在同一次会话的不同请求之间来共享数据。

优点:是 HTTP 中支持的技术,浏览器对于 Cookie 的自动发送和接受存储都是自动的,不需要我们手动操作

缺点:

  1. 移动端的 APP 无法使用 cookie
  2. 不是很安全因为用户可以自己禁用 cookie
  3. 跨域的话不能用 cookie(协议,IP地址,端口三者缺一就是跨域)

Session 数据存储在服务器(服务端会话跟踪技术)

比如浏览器第一次请求服务器的时候,这时候服务器会创建一个会话对象 Session,可以往 Session 中存储一些数据,且每一个会话对象都有一个 JsessionID。【HttpSession 的 setAttribute()方法】

接下来服务器在给浏览器相应数据的时候,就会把 Session 的 ID 通过 Cookie 响应给浏览器(放在响应头 Set-Cookie 中,cookie 的名字是固定的 JsessionID ------代表的服务器端会话对象 Session 的 ID)浏览器会自动识别这个响应头,然后将 Cookie 存在浏览器本地。

接下来,在后续的每一次请求当中,都会将 Cookie 携带到服务端(放在请求头 Cookie 中)。服务器拿到 JSESSIONID 这个 Cookie 的值,也就是 Session 的ID。拿到 ID 之后,就会从众多的 Session 当中来找到当前请求对应的会话对象Session。【HttpSession 的 getAttribute() 方法】

这样就可以 通过 Session 会话对象,在同一次会话的多次请求之间来共享数据了
优点: Session 是存储在服务端的,安全
缺点:

1.服务器集群不能直接用 Session。请求->负载均衡服务器->后端服务器 tomcat 集群

2.还有 Cookie 的问题:

a. 不能跨域(IP 地址,端口号,协议)

b. 用户可以自己禁用 Cookie

c. 移动端不能用 Cookie

令牌技术

令牌,其实它就是一个用户身份的标识,其实本质就是一个字符串。

在请求登录接口的时候,如果登录成功,我就可以生成一个令牌,令牌就是用户的合法身份凭证。接下来我在响应数据的时候,我就可以直接将令牌响应给前端。

前端程序接收到令牌之后,就需要将这个令牌存储起来。这个存储可以存储在 cookie 当中,也可以存储在其他的存储空间(比如:localStorage)当中。

接下来,在后续的每一次请求当中,都需要将令牌携带到服务端。携带到服务端之后,接下来我们就需要来校验令牌的有效性。如果令牌是有效的,就说明用户已经执行了登录操作,如果令牌是无效的,就说明用户之前并未执行登录操作。

如果是在同一次会话的多次请求之间,我们想共享数据,只需要将共享的数据存储在令牌当中就可以了。

优点:1. 支持 PC 端 支持移动端

  1. 解决了集群环境下的认证问题(因为不需要在服务器端存储数据)

  2. 减轻了服务器的存储压力(令牌存储在客户端)

缺点:1. 需要自己实现令牌的生成,令牌的传递,令牌的校验

相关推荐
StayInLove1 分钟前
G1垃圾回收器日志详解
java·开发语言
对许5 分钟前
SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder“
java·log4j
无尽的大道9 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
小鑫记得努力18 分钟前
Java类和对象(下篇)
java
binishuaio22 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE23 分钟前
【Java SE】StringBuffer
java·开发语言
老友@23 分钟前
aspose如何获取PPT放映页“切换”的“持续时间”值
java·powerpoint·aspose
superman超哥31 分钟前
04 深入 Oracle 并发世界:MVCC、锁、闩锁、事务隔离与并发性能优化的探索
数据库·oracle·性能优化·dba
minihuabei37 分钟前
linux centos 安装redis
linux·redis·centos
wrx繁星点点39 分钟前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式