前端同学应该了解的 “会话控制”

292 阅读9分钟

前言

同学,你好!我是 嘟老板。不知你是否发现,目前大多数应用,都会有登录功能,而且登录之后再次访问,还可以识别到我们的身份,不需要重复登录。这是为什么呢?又是怎么实现的呢?这就是我们今天要聊的主题 - 会话控制

阅读本文您将收获:

  1. 了解 会话控制 的定义及作用。
  2. 了解 会话控制 的三种实现方法。
  3. 本文偏理论,无逻辑代码,后续会针对每种方式,单独分享实现代码。

什么是会话控制

定义 会话控制 之前,我们先说说什么是会话?

会话就是 客户端与服务端之间进行的一次完整的交互过程

通常在访问网站时,网站客户端会向服务端发送请求,服务端接收到请求后,会对请求做出响应,返回给客户端。

所以会话控制,实际上就是对 网站客户端与服务端之间的 http 请求、响应交互的控制,可以达到记录、跟踪和识别用户的目的

为什么需要会话控制

客户端与服务端通过 http 进行通信,而 http 是一种无状态的协议,对于服务端来说,客户端每次发起的请求,都是一个新的请求,多次发起的请求无法确定是否来自同一客户端,自然也无法确定是否来自同一个用户。

而在实际的应用中,往往需要明确发起请求的用户信息,以执行特定的业务逻辑,比如登录状态验证、权限控制、浏览历史等。

有了会话控制,就可以完美解决以上问题。

会话控制的实现方式

会话控制可以通过以下三种方式实现:

  • Cookie
  • Session
  • JWT

Cookie

什么是 Cookie

Cookie 就是浏览器存储的一段文本信息,由服务端生成,发送给客户端后,浏览器会以 key/value 的格式存储。若浏览器设置了启用 Cookie,下次向同一服务发送请求时,会在请求头自动带上所有的 Cookie

Cookie域名安全的,不同域名的网站之间,Cookie 不会共享。

比如我在访问网站 a.com 时,浏览器存储了一段 Cookie,访问 b.com 时,无法访问网站 a.comCookie 信息,只能访问 b.com 自己的 Cookie

Cookie 的创建过程

服务端接收到客户端发送的 Http 请求后,可以在响应头上添加一个或多个 Set-Cookie 选项。客户端接收到响应后,会将 Cookie 保存下来,后续再发送请求时,会将所有的 Cookie 放到请求头的 Cookie 选项上,一并发送给服务端。

比如,服务端创建两个 Cookiename=dulaoban,password=123,创建 Cookie 的大致流程如下:

  1. 客户端向服务端发送请求,服务端接收后,添加两个 Set-Cookie 选项。

image.png

  1. 浏览器收到响应,将两个 Cookie 保存到浏览器端。

image.png

  1. 后续再发送请求时,会将所有 Cookie 一并发送到服务端。

image.png

整个流程示意图如下:

image.png

Cookie 实现会话控制的原理

正如前面的例子,我们可以将用户名等用户信息保存到 Cookie 中,作为用户身份验证的依据。服务端接收到请求后,可以验证 Cookie 中是否存在用户信息,若没有,则表明当前请求来源不明,需要提醒用户去登录,调用登录接口时设置 Cookie 并返回给客户端;若存在,则可以明确请求用户,便可针对用户执行后续的业务逻辑。

不过单纯使用 Cookie 来实现会话控制,缺点也很明显。因为 Cookie明文存储在浏览器端的,对于用户来说相当于完全开放,只要用户会 F12 打开控制台,就能拿到,存在极大的安全隐患。

那怎么办呢?没关系,接下来要说的 SessionCookie 一起食用,效果更佳。

Session

什么是 Session

相对于 Cookie 保存在浏览器端,Session 则是保存在服务端,可以存储在内存中,也可以写到文件数据库中。

服务端会为每一个用户生成特定的 Session,存储 用户会话所需的属性和配置信息

Session 是存储在服务端的,如何识别客户端的请求属于哪个用户呢?这就需要 Cookie 的帮助了。服务端在生成 Session 的同时,还会生成一个全局唯一的 SessionID,并保存在浏览器的 Cookie 中。客户端在请求时,携带了 SessionIDCookie,就可以识别用户,否则就是来路不明的请求,先去登录了再来。

Session 实现会话控制的原理

处理流程大致如下:

  1. 客户端初次发送请求,服务端验证 Cookie 中是否存在 SessionID,发现不存在,提示客户端需要登录
  2. 登录接口中为用户创建 SeesionSessionID,并将 SessionID 放到 Cookie 中,返回给客户端。
  3. 客户端存储 Cookie,下次请求时带上,服务端接收请求发现有 SessionID,验证 Session 是否状态正常,OK 则执行后续逻辑,否则可提醒重新登录或生成新的 Session

流程示意图大致如下:

image.png

Session 与 Cookie 的区别

可以看出,SessionCookie 都能实现会话控制,那在技术方案上如何选择呢?

以下是两者的一些差异点,可作为选型的参考:

  • 存储

    Cookie 存储在客户端,单个 Cookie 存储的数据不能超过 4K;
    Session 存储在服务端,存储大小无限制;

  • 隐私策略

    Cookie 明文存储在客户端,相当于对用户开放,不适合存储账号密码等敏感信息;
    Session 保存在服务端,对用户不可见,相对安全,可以保存敏感信息等;

  • 有效期

    Cookie 可以通过设置 过期时间,确定有效期,可设为永久有效;
    Session 因为保存在服务端,设为永久有效会导致 Session 不断增多,无法释放,导致内存问题。

  • 浏览器支持

    Cookie 存储在浏览器端,需要浏览器支持,若浏览器禁用 Cookie,则不可用。
    Session 虽然需要借助 Cookie 存储 SessionID,但若浏览器禁用 Cookie,可以通过将 SessionID 拼接到 URL 的方式,传递给服务端。

  • 跨域支持

    Cookie 可以通过设置 domain 属性,允许子域名网站访问。
    Session 不支持跨域访问,只在当前域名网站可用。

  • 服务器压力

    Cookie 存储在浏览器端,对服务器无影响。
    Session 存储在服务端,若网站并发量很大,会耗费大量的内存,对于服务器压力较大。

JWT(Json Web Token)

什么是 Token

Token 实质上就是服务端生成的一段加密字符串,用于保存用户信息。

什么是 JWT

JWT 是目前最流行的跨域认证解决方案,可用于基于 Token 的身份认证,使得 Token 的生成和校验更加标准化。

通常服务端认证成功之后,会返回一个 JSON 对象给客户端,一般包含用户信息,后续客户端的请求都需要携带上这个 JSON,供服务端进行校验。

这就意味着 JWT 需要保存在客户端,服务端不需要再保存 Session 了。

然而通常我们看到的 JWT 是这样的:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTc2NzkxNzMsImNzX3VzZXIiOiJ7XCJhY2NvdW50XCI6XCJ6aG91d2Vpd2VuMDRcIixcImV4dHJhTWFwXCI6e1wiZmllbGRNYXBcIjp7fSxcInJvbGVNYXBcIjp7fX0sXCJpZFwiOlwiMTUzNjMwODMyODY0OTIxMTkwNlwiLFwibmFtZVwiOlwiOCoqXCIsXCJzdXBlckFkbWluXCI6dHJ1ZSxcInRlbmFudENvZGVcIjpcImNzXCJ9IiwidXNlcl9uYW1lIjoiemhvdXdlaXdlbjA0IiwianRpIjoiZTZmZjczYTctNjM2My00MjNkLThiY2ItM2ZkMzk2N2FhYjg4IiwiY2xpZW50X2lkIjoiY3MiLCJzY29wZSI6WyJhbGwiXX0.qBw_dYzcem2tBk1SaTCbl0Ryggr8LgbUjasHFl0ZKFNq8OE7iAP8fD6NXFkGrA50aO64p1SOcLcC6Trd8StyhUvZ34cQ6dEKzdKGeE3FxMW0F0Z7QVKLMR8WSdcxM4mNWEpQRVBr_BJX9yipX2opQlGYvg1jCZCTBwdeM32YDJBjMLmFhSqp9yCdUXCerFwLiA525P4esb85f8Jta3BZKskkT3WOjerYDtK9jTvS9Ntt1Nu6GShyLB9f_ay4BXCWMCAXwHzRcWGKf64fADDAsQmXKqBb7TIlo6Efmypzq7zdb0oLfvkreTtFN-OKtpLD2OKVYB33g-A2stC8uZXM7Q

很明显是一段加密字符串,以 点(.) 分割成三段,为什么是这样的呢?不说是 JSON 格式吗?

因为 JWT 里面保存了用户信息,也可能会包含敏感数据,若直接明文传递的话,安全性就得不到保障。因此前端拿到的 JWT,通常都是服务端加密后的字符串。

请求携带 JWT 的常用方式

客户端接收到服务端返回的 JWT 后,需要存储到前端,可以考虑存储为 Cookie,但是更推荐存储到 LocalStorage/SessionStorage 中。

若存储到 Cookie,每次请求都会自动携带,缺点是无法实现跨域。

因此更合理的方式是放到请求头 Authorization 选项中。

Authorization: Bearer <token>

JWT 实现会话控制的原理

以下是 JWT 实现会话控制的大致流程:

  1. 服务端接收客户端请求,验证请求头 Authorization 携带的 token,若校验不通过,则提示去登录。
  2. 登录成功后,根据用户信息,生成新的 token,返回给客户端,后续客户端的请求都携带最新的 token
  3. 客户端后续再次请求时,token 验证通过,即可执行后续的业务逻辑。

流程示意图如下:

image.png

JWT 的优缺点

优势

  • 无状态token 保存在客户端,不需要在服务端保存 session,而且相对 Cookie 来说,会进行加密处理,保证安全性。
  • 避免 CSRF(跨域请求伪造)CSRF 多是依赖请求自动携带 Cookie 的特性,因此经常发生于 Cookie 验证的网站。而 JWT 是网站主动添加到 Authorization 请求头的,不会自动携带。
  • 移动端使用JWT 可以在客户端存储和使用,不像 Cookie ,比较依赖于浏览器。
  • 单点登录JWT 不存在跨域问题,不同域名的网站都可以携带。

缺点

因为 JWT 的无状态特性,导致 JWT 不可控,服务端无法在有效期内作废一个 token,只能等 token 过期。

结语

本文重点介绍了会话控制的定义、作用及三种实现方式,旨在帮助同学了解会话控制的可行性实现方案。后续会把三种方式挨个实现一下,感兴趣的同学蹲一下吧。

如果您对文章内容有任何疑问或想深入讨论,欢迎评论区留下您的问题和见解。

技术简而不凡,创新生生不息。我是 嘟老板,咱们下期再会。


往期推荐