Cookie、Session及Token详解

发布时间 2023-08-23 18:34:39作者: kybky

Cookie

Cookie,有时也用其复数形式 Cookies,类型为“小型文本文件”,是某些网站为了辨别用户身份,进行 Session 跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息

以加入购物车为例,每次浏览器请求后 server 都会将本次商品 id 存储在 Cookie 中返回给客户端,客户端会将 Cookie 保存在本地,下一次再将上次保存在本地的 Cookie 传给 server 就行了,这样每个 Cookie 都保存着用户的商品 id,购买记录也就不会丢失了

随着购物车内的商品越来越多,每次请求的 Cookie 也越来越大,这对每个请求来说是一个很大的负担

Session

由于用户的购物车信息都会保存在 Server 中,所以在 Cookie 里只要保存能识别用户身份的信息,知道是谁发起了加入购物车操作即可,这样每次请求后只要在 Cookie 里带上用户的身份信息,请求体里也只要带上本次加入购物车的商品 id,大大减少了 Cookie 的体积大小,我们把这种能识别哪个请求由哪个用户发起的机制称为 Session(会话机制),生成的能识别用户身份信息的字符串称为 sessionid,它的工作机制如下

  1. 首先用户登录,server 会为用户生成一个 session,为其分配唯一的 sessionid,这个 sessionid 是与某个客户端用户绑定的,也就是说根据此 sessionid(假设为 abc) 可以查询到它到底是哪个用户
  2. 服务器然后将此 sessionid 通过 Cookie 传给浏览器
  3. 之后浏览器的每次请求中只要在 Cookie 里带上 sessionid=abc 这一个键值对
  4. server 将用户Cookie里面记录的sessionid和服务器内存中的sessionid进行比对,从而找到这个用户对应的session并恢复之前的状态信息

Cookie 是存储在 client 的,而 session 保存在 server,sessionId 需要借助 Cookie 的传递才有意义

session 的不足

上述情况能正常工作是因为我们假设 server 是单机工作的,但实际在生产上,为了保障高可用,一般服务器至少需要两台机器,通过负载均衡的方式来决定到底请求该传到哪台机器上

那么session怎么办呢,假设登录请求发到了 A 机器,A 机器生成了 session 并在 Cookie 里添加 sessionId 返回给了浏览器,下次添加购物车时如果请求发到了 B 或者 C,由于 session 是在 A 机器生成的,此时的 B,C 是找不到 session 的,那么就会发生无法添加购物车的错误,就得重新登录了,那么这个时候该怎么办呢?
主要有以下三种解决方式:

session 复制

A 生成 session 后复制到 B, C,这样每台机器都有一份 session,无论添加购物车的请求打到哪台机器,由于 session 都能找到,所以不会有问题

缺点:

  1. 同一样的一份 session 保存了多份,数据冗余
  2. 如果节点少还好,但如果节点多的话,可能需要部署成千上万台机器,这样节点增多复制造成的性能消耗也会很大

session 粘连

这种方式是让每个客户端请求只发到固定的一台机器上,比如浏览器登录请求发到 A 机器后,后续所有的添加购物车请求也都发到 A 机器上,Nginx 的 sticky 模块可以支持这种方式,支持按 ip 或 Cookie 粘连等等,如按 ip 粘连方式如下

upstream tomcats {
  ip_hash;
  server 10.1.1.107:88;
  server 10.1.1.132:80;
}

这样的话每个 client 请求到达 Nginx 后,只要它的 ip 不变,根据 ip hash 算出来的值会发到固定的机器上,也就不存在 session 找不到的问题了

缺点:机器挂了就无法找到session

session 共享

这种方式也是目前各大公司普遍采用的方案,将 session 保存在 redis,memcached 等中间件中,请求到来时,各个机器去这些中间件取一下 session 即可

每个请求都要去 redis 取一下 session,多了一次内部连接,消耗了一点性能,不是什么大问题

Token

首先请求方输入自己的用户名、密码,然后 server 据此生成 token,客户端拿到 token 后会保存到本地,之后向 server 请求时在请求头带上此 token 即可
server 会有一套校验机制,校验这个 token 是否合法,在 token 中也会携带 uid 信息

token 主要由三部分组成:

  1. header:指定了签名算法,不做加密,只做一般的base64编码
  2. payload:存放用户信息,不做加密,只做一般的base64编码
  3. Signature:签名,server 根据 header 知道它该用哪种签名算法,再用密钥根据此签名算法对 head + payload 生成签名,这样一个 token 就生成了,因此这个签名中包含三部分内容
  • header
  • payload
  • secret(盐,是一个私钥)

流程:

  1. 浏览器访问服务器,服务器为其生成一个token并传给浏览器
  2. 浏览器下次再次访问的时候就发送这个token
  3. 当 server 收到浏览器传过来的 token 时,它会首先取出token中的 header + payload,使用 secret 生成签名
  4. 将此签名与浏览器发来的token中的Signature比对,如果成功则说明签名是合法的,即 token 是合法的
  5. 从 payload 中直接就可以获取用户的状态信息,避免了像 session 那样要从 redis 去取的开销

三者区别


  • Cookie不支持跨域访问、单点登录,Token支持跨域访问、单点登录
  • Token支持移动平台,可扩展性好,Cookie不支持
  • Cookie是个数据载体用来传递数据
  • Session生成在服务端同时保存在服务端,只有Cookie作为载体来将SessionID传送
  • Token生成在服务端保存在客户端,服务端中会保存secret