前言:
本文中的用户端(client)约等于浏览器。
服务端就是sever。

cookie、session、token都是由sever生成,保存在client端。
三者最大的不同在于服务端对cookie、session、token的处理。

cookie
1、在client输入账号密码,点击登录发送请求 a到sever,sever验证账号密码通过,获知用户信息。
2、这个时候sever生成cookie,在请求a的response中用Set-Cookie字段把cookie信息返回给发送请求的client。client见到Set-Cookie之后把cookie记录在本地。
3、client再次发送请求b的时候会携带cookie,让sever知道这个请求的发起者的身份(或者权限)。

session
1、在client输入账号密码,点击登录发送请求 a到sever,sever验证账号密码通过,获知用户信息。
2、这个时候sever生成有对应关系的key和value。value中保存用户信息(下文用userMessage指代),userMessage需要存储在服务器端(一般是保存在内存数据库中,这样查的快)。key是一长串无序字符串,这里的key(下文用sessionString指代)就是session。
3、sessionString作为cookie的一部分发送给client,cookie的内容中由sever添加一个特殊的字段(字段名可以是session、sessionId、sys_session等等),这个字段用于传输和存储sessionString(举例: 特殊字段名a_sys_session 对应 sessionString) 。
在请求a的response中用Set-Cookie字段把cookie信息返回给发送请求的client,client见到Set-Cookie之后把cookie记录在本地,a_sys_session和sessionString也被记录在本地。
4、client再次发送请求b的时候会携带cookie,cookie中又有a_sys_session字段,当sever拿到cookie后,从cookie中提取出a_sys_session字段对应的sessionString。
5、通过sessionString查询userMessage,获取用户信息(也有可能查询不到,如过期了,或者sessionString被改了)。获取用户信息之后,sever知道这个请求的发起者的身份(或者权限)。

image.png

token
1、在client输入账号密码,点击登录发送请求 a到sever,sever验证账号密码通过,获知用户信息。
2、sever将用户信息(下文用userMessage2指代)拿出来格式化为一种特定的格式(如string、object)。sever自身需要有一个秘钥(下文用secretKey指代),这个秘钥保存在服务器端,将userMessage2和secretKey通过加密算法(createFunction)生成一段新的字符串(下文用secretString2指代)。将userMessage2和secretString2通过某种易拆分的方式加工成一个新字符串(concatString2),这里的concatString2就是token。sever端无需保存token。
3、concatString2需要返回给client,这时是有两种方式可选的。
3.1其一是作为cookie的一部分发送给client。cookie的内容中由sever添加一个特殊的字段(字段名可以是token、sys_token等等),这个字段用于传输和存储concatString2(举例: 特殊字段名a_sys_token对应 concatString2) 。
在请求a的response中用Set-Cookie字段把cookie信息返回给发送请求的client,client见到Set-Cookie之后把cookie记录在本地,a_sys_token和concatString2也被记录在本地。client再次发送请求b的时候会通过cookie携带token信息。

3.2其二是作为特定的返回字段交给client自行存储。这种情况下token需要在客户端接收到请求a的response之后用程序实现将token存储到sessionStorage或localStorage中。另外每次发送请求时都需要将token携带上,传递给sever。这种情况下携带token信息的方式的通用做法是将token放在请求头的Authorization字段。

4、client再次发送请求b的时候携带token信息到达sever后,sever解析得到concatString2,再通过concatString2拆分出userMessage2和secretString2。
5、通过解析得到的userMessage2加上服务端保存的secretKey+createFunction重新生成newSecretString,校验newSecretString和secretString2是否一致。如果校验通过,则确认userMessage2是正确的用户信息。

三者安全性对比:
cookie的安全性最差,因为cookie把用户信息放在了本地,可能会被修改。虽然我们可以通过设置httpOnly禁止通过js代码改动cookie,但如果从浏览器中复制cookie,再修改cookie用http工具(如postman)发送请求,是有可能获取到额外的信息的。
session把用户信息存储在的sever端,token有校验的过程,两者的安全性远强于cookie。session和token的安全性在同一级别,硬要分个高下我感觉session稍强。但要说能改token的信息,那必须同时获知创建token的secretKey和createFunction,这也得是有内鬼才行吧。

session和token的优劣势分析:
由于sever可能对接大量的client,也就需要存放大量的 session,这样会导致数据库的IO压力,要考虑用户数量。此外如果服务器端是一个集群,为了同步登录态,需要将 session 同步到每一台机器上,无形中增加了sever的维护成本。
token的优势在于服务器端不需要存储token,所以不会对服务器端造成额外的存储压力,即使是服务器集群,也不需要增加维护成本。
token的实现方式较为灵活,前端有很多发挥空间,不一定要保存在Cookie 中。
token 下发之后,只要在生效时间之内,就一直有效,如果服务器端想收回此 token 的权限,并不容易。(token的做法我没实践过,不知道有什么方式可以收回token权限,盲区)

完结。

同步更新到自己的语雀
https://www.yuque.com/diracke...


DiracKeeko
125 声望2 粉丝