在理解 Session Cookie 概念前,我们需要先了解下 HTTP 协议的特点。HTTP 是无状态协议,用于传输数据。 它启用了客户端和服务器端之间的通信。 最初是为了在Web浏览器和Web服务器之间建立连接而建立的。
注意:HTTP 是无状态的。什么叫无状态?比如你在上网冲浪,某购物平台买东西,当你将商品加入购物车时,切换到另一个页面,购物车的东西就消失了。因为每次 HTTP 请求对于服务端来说都是新的,服务端并不知道你是谁。
那有没有办法解决这个问题呢?聪明如你,如果我第一次请求后,服务端给我一个 key,每次提交请求带上它,那服务端是不是就知道我是谁了呢?Session Cookie 其实就是基于这样的设计。
我们来看一下基于 Session 的认证机制。
- 用户使用用户名密码登录网站。服务端生成 Session 放到内存中。
- 服务端往浏览器里设置 session-id (相当于上文提到的 key,唯一性由服务端保证)
- 客服端(指浏览器)向服务端发起获取用户数据请求,并携带 Cookie。
- 服务端通过 session-id 查找对应 Session ,找到即返回数据。
写到这里,有同学可能会问了,单体应用这样实现没有问题。如果应用要做负载均衡,物理机甚至都不在一起,这种情形下怎么维护 Session 呢?
在笔者实际参与的项目中,比如 Laravel 项目,我们通常会把 Session 放到 Redis 存储,多个应用使用同一个 DB,这样也是一种解决办法。
那有没有其他的方式呢?有,我们可以不是用 Session Cookie 这种结构,下面介绍一下 JWT (JSON Web Token)。
- 用户使用用户名密码登录到服务器,服务器为用户创建 JWT。
- 服务器响应 JWT ,客户端将其存在 Local Storage 下。
- 客户端发起数据请求,通过在 HTTP 头部设置 JWT ,随请求到服务端。
- 服务端使用私钥去解密 JWT,通过即响应请求数据。
JWT 由三部分组成
- Header 头部,描述 JWT 元数据
- Payload 载荷,实际传输数据,可以是业务数据。
- Signature 签名,是对前两部分的签名,防止数据篡改。
使用 JWT 相当于服务端把 Session 数据的维护由服务端转移到客户端。服务端不需要额外的存储,每次验证只要校验 JWT 是否合法即可,减少服务端的存储压力。
但 JWT 有这么完美么?恐怕不一定,笔者在整理这篇文章时,发现有人就不同意。
大家可以看看这篇文章:Stop using JWT for sessions 其中列举了 JWT 的一些缺陷。
这里简单提一下:
- 占用较多的空间。每次请求都要携带 JWT base64 编码的内容。
- 没有办法主动使一个 JWT 失效,除了它自己过期了。
- 数据过时问题,在 JWT 失效前,其中 Payload 数据可能会过时。
总结:使用哪种方还是需要看具体的业务场景,不要盲目跟风。
参考