Session、Cookie与Token

http协议是无状态协议

协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。

HTTP协议是无状态的协议,无状态是指协议对于事务处理没有记忆功能。

一旦数据交换完毕,本次客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。

也就是说,假如后面连接的处理需要前面的信息,则前面的信息必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要前面信息时,应答就较快。

直观地说,就是每个请求都是独立的,与前面的请求和后面的请求都是没有直接联系的。

而实际的情况是,如今web应用中使用http协议,大多数时候我们希望是有状态的。大多数网站都需要用户注册与登录后,才能进行后续的操作,比如电商平台,服务端势必需要识别用户,并跟踪用户,这样才能知道这个用户是谁,他的购物车里有几件衣服。

为什么不改进http协议使之有状态

最初的http协议只是用来浏览静态文件的,无状态协议已经足够,这样实现的负担也很轻(相对来说,实现有状态的代价是很高的,要维护状态,根据状态来操作。)。随着web的发展,它需要变得有状态,但是不是就要修改http协议使之有状态呢?是不需要的。因为我们经常长时间逗留在某一个网页,然后才进入到另一个网页,如果在这两个页面之间维持状态,代价是很高的。其次,历史让http无状态,但是现在对http提出了新的要求,按照软件领域的通常做法是,保留历史经验,在http协议上再加上一层实现我们的目的(“再加上一层,你可以做任何事”)。所以引入了其他状态机制来实现这种有状态的连接。

哪些方法可以弥补 HTTP 的无状态特性:

Session、Cookie与Token

会话管理的发展史

1.随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,大家面临一个问题,那就是要管理会话,也就是说必须把每个人区分开,这就是一个不小的挑战,因为HTTP请求是无状态的,所以想出的办法就是给每人发一个会话标识(session id), 说白了就是一个随机的字串,每个人收到的都不一样,每次大家向我发起HTTP请求的时候,把这个session id给一并捎过来,服务端和本地保存的session一比较,就能区分开谁是谁了。

2.这样大家很嗨皮了,可是服务器就不嗨皮了,每个人只需要保存自己的session id,而服务器要保存所有人的session id !如果访问服务器的请求多了, 就得由成千上万,甚至几十万个。

这对服务器说是一个巨大的开销 ,而且更可恨的是,还严重的限制了服务器扩展能力, 比如说我水平扩展用两个机器组成了一个集群, 小F通过机器A登录了系统, 那session id会保存在机器A上, 假设小F的下一次请求被转发到机器B怎么办?机器B可没有小F的 session id啊。

有时候会采用一点小伎俩: session sticky (比如Nginx的sticky模块和ip_hash), 就是让小F的请求一直粘连在机器A上, 但是这也不管用, 要是机器A挂掉了, 还得转到机器B去。

那只好做session 的复制了, 把session id 在两个机器之间搬来搬去, 快累死了。

 后来有个叫Memcached的支了招:把session id 集中存储到一个地方, 所有的机器都来访问这个地方的数据, 这样一来,就不用复制了, 但是增加了单点失败的可能性, 要是那个负责session 的机器挂了, 所有人都得重新登录一遍, 估计得被人骂死。

也尝试把这个单点的机器也搞出集群,增加可靠性, 但不管如何, 这小小的session 对服务端来说是一个沉重的负担。

3.于是有人就一直在思考, 我为什么要保存这可恶的session呢, 只让每个客户端去保存该多好?

可是如果不保存这些session id , 怎么验证客户端发给我的session id 的确是我生成的呢? 如果不去验证,我们都不知道他们是不是合法登录的用户, 那些不怀好意的家伙们就可以伪造session id , 为所欲为了。

嗯,对了,关键点就是验证 !

比如说, 小F第一次登录了系统, 我给他发一个令牌(token), 里边包含了小F的 user id, 下一次小F 再次通过Http 请求访问我的时候, 把这个token 通过Http header 带过来。

不过这和session id没有本质区别啊, 任何人都可以可以伪造, 所以我得想点儿办法, 让别人伪造不了。

那就对数据做一个签名吧, 比如说我用HMAC-SHA256 算法,加上一个只有我才知道的密钥, 对数据做一个签名, 把这个签名和数据一起作为token , 由于密钥别人不知道, 就无法伪造token了。

这个token 我不保存, 当小F把这个token 给我发过来的时候,我再用同样的HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名, 和token 中的签名做个比较, 如果相同, 我就知道小F已经登录过了,并且可以直接取到小F的user id , 如果不相同, 数据部分肯定被人篡改过, 我就告诉发送者:对不起,没有认证。

Token 中的数据是明文保存的(虽然我会用Base64做下编码, 但那不是加密), 还是可以被别人看到的, 所以我不能在其中保存像密码这样的敏感信息。

当然, 如果一个人的token 被别人偷走了, 那我也没办法, 我也会认为小偷就是合法用户, 这其实和一个人的session id 被别人偷走是一样的。

这样一来, 我就不保存session id 了, 我只是生成token , 然后验证token , 我用我的CPU计算时间获取了我的session 存储空间 !

解除了session id这个负担, 可以说是无事一身轻, 我的机器集群现在可以轻松地做水平扩展, 用户访问量增大, 直接加机器就行。这种无状态的感觉实在是太好了!

Cookie

Cookie意为“甜饼”,Cookie是客户端保存用户信息的一种机制,实际上是一小段以kv形式保存在客户端本地的数据(两种cookie的存储方式不同)。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。

cookie的创建

当接收到客户端发出的 HTTP 请求时,服务器会发送带有响应的 Set-Cookie 标头,下面是一个发送 Cookie 的例子

此标头通知客户端存储 Cookie

之后,客户端对服务器的每个新请求,浏览器会将以前存储的 Cookie 连同一起发送回服务器。

 cookie的常用属性:

 cookie的有效期与分类

cookie的maxAge决定着Cookie的有效期,单位为秒(Second)。Cookie中通过getMaxAge()方法与setMaxAge(int maxAge)方法来读写maxAge属性。

  •        如果maxAge为负数,则表示该Cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该Cookie即失效。maxAge为负数的Cookie,为临时性Cookie,不会被持久化,不会被写到Cookie文件中。此类Cookie信息保存在浏览器内存中,因此关闭浏览器该Cookie就消失了。Cookie默认的maxAge值为–1。
  •        如果maxAge为正数,则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。
  •   如果maxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie的方法,因此通过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除。

 

根据上述Cookie的有效期,分为两种类型 Cookies,一种是 Session Cookies(会话Cookie),一种是 Persistent Cookies(持久性 Cookie)。

如果 Cookie 不包含到期日期(即maxAge为负数),则将其视为会话 Cookie。会话 Cookie 存储在内存中,永远不会写入磁盘,当浏览器关闭时,此后 Cookie 将永久丢失。

如果 Cookie 包含有效期(即maxAge为正数) ,则将其视为持久性 Cookie。持久性 Cookie存储在磁盘中,以文本文件形式保存,到了指定的日期,Cookie 将从磁盘中删除。例如谷歌浏览器在我电脑上的位置:

浏览器上常用的记住密码功能就是使用永久cookie写在客户端电脑,下次登录时,自动将cookie信息附加发送给服务端,此类操作只适用于个人电脑,因为cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗。

cookie的主要用途

  • 会话管理

  登陆、购物车、游戏得分或者服务器应该记住的其他内容。比如淘宝登陆后,再点开一个商品页面,依然是登录状态,即便关闭了浏览器,再次开启浏览器,依然会是登录状态。

  • 个性化

  用户偏好、主题或者其他设置,比如QQ和搜狗的个性设置

  • 追踪

  记录和分析用户行为,如记录用户访问次数

Session(狭义,作为一种会话实现的方式)

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

服务器给每个客户端分配不同的“身份标识”,同时在服务器本地把所有人的“身份标识”统一存储管理;当客户端每次向服务器发请求的时候,都带上自己的“身份标识”,服务器和本地的数据一对比,就知道这个请求来自于谁了。

至于客户端怎么保存这个“身份标识”,可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 的方式。

也就是说,Cookie和Session组合使用可以实现网站对于用户的身份认证,但session并不强依赖cookie(见session的其他实现)

session的创建(基于cookie)

服务器第一次接收到请求时,开辟一块 Session 空间(创建了Session对象),同时生成一个 sessionId ,并通过响应头的 **Set-Cookie:JSESSIONID=XXXXXXX **命令,向客户端发送要求设置 Cookie 的响应; 客户端收到响应后,在本机客户端设置了一个 **JSESSIONID=XXXXXXX **的 Cookie 信息,该 Cookie 的过期时间为浏览器会话结束;

接下来客户端每次向同一个网站发送请求时,请求头都会带上该 Cookie信息(包含 sessionId ), 然后,服务器通过读取请求头中的 Cookie 信息,获取名称为 JSESSIONID 的值,得到此次请求的 sessionId,这个sessionId就是每个客户端的“身份标识”,比如:

Cookie: $Version=1; Skin=new;jsessionid=5F4771183629C9834F8382E23BE13C4C

session的其他实现

如果客户端禁用了cookie,通常有两种方法实现session而不依赖cookie。

1)URL重写,原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。即每次HTTP交互,URL后面都会被附加上一个诸如“;jsessionid=XXX” 这样的参数,服务器通过解析URL地址获得Session的id。

2)表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如:

<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>

session的生命周期

  • Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
  • Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问html、image等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。
  • Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
  • 由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。 Tomcat 中 Session 的默认失效时间为 20 分钟。 
  • 关机,关闭tomcat,应用reload,调用 Session 的 invalidate 方法等也会造成session生命周期的结束

session的存储

在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。
 

cookie与session的总结

Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在内存、集群、数据库、文件中;比如使用一些缓存服务比如Memcached之类的来放。
Cookie是客户端保存用户信息的一种机制(cookie也是服务端产生的),用来记录用户的一些信息。

session 因为 session id 的存在,通常要借助 cookie 实现,但这并非必要,只能说是通用性较好的一种实现方案。 

总之,cookie是客户端的一个通行证(服务端发的),session是服务端的一本档案册,任何安全的校验必须要在服务端上完成,也就是说通行证终究要被拿到档案册里进行匹配校验。

Token

session(服务端保存登录状态)方式的一些问题:

1、服务器压力增大

通常session是存储在内存中的,每个用户通过认证之后都会将session数据保存在服务器的内存中,而当用户量增大时,服务器的压力增大。

2、可扩充性问题  

如果将来搭建了多个服务器,虽然每个服务器都执行的是同样的业务逻辑,但是session数据是保存在内存中的(不是共享的),用户第一次访问的是服务器A,当用户再次请求时可能访问的是另外一台服务器B,服务器B获取不到session信息,就判定用户没有登陆过。

3、CSRF跨站伪造请求攻击

session是基于cookie进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

4、Session Cookies 只能用在单节点的域或者它的子域中有效,即不支持跨域认证。

比如A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录。

一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是持久层万一挂了,就会单点失败。

另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器,由不同的服务器去验证请求,JWT 就是这种方案的一个代表。

我们发现淘宝和天猫就是这样,用浏览器同时打开这两个网站,只要登录了其中的一个,另一个就会自动登录。

Token原理(Json Web Token 的简称就是 JWT,通常可以称为 json令牌)

JWT 的原理是,一个请求过来,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

{
  "姓名": "张三",
  "角色": "管理员",
  "到期时间": "2018年7月1日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

 JWT的数据结构

实际的 JWT 大概就像下面这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的。

JWT 的三个部分依次如下:

  • Header(头部)
  • Payload(负载)
  • Signature(签名)

即 Header.Payload.Signature

1.Header

Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。

{
  "alg": "HS256",
  "typ": "JWT"
}

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT

指定类型和签名算法后,Json 块被 Base64Url 编码成字符串,形成 JWT 的第一部分。

2.Payload

Payload 部分也是一个 JSON 对象,用来存放用户的实际需要传递的数据。

这里JWT 规定了7个官方字段供选用:

iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号

除了官方字段,还可以在这个部分定义私有字段,比如:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

然后 payload Json 块会被Base64Url 编码形成 JWT 的第二部分。

3.signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

ps:Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

JWT 的使用方式

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage(通过js代码写入Local Storage,通过js获取,并不会像cookie一样自动携带)。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。

session与token的总结

token和session其实都是为了解决HTTP协议无状态的问题,session一般翻译为会话,而token更多的时候是翻译为令牌;

其实token与session的问题是一种时间与空间的博弈问题,session需要服务端的存储空间(无论是缓存,文件,数据库等等),是空间换时间;token需要服务端的解密计算,是时间换空间;至于牺牲时间与还是牺牲空间,需要具体情况具体分析。

session:我发给你一张写着身份证号码的纸片,你每次来办事,我去后台查一下你的号码和局里留底的身份证对不对得上。 

token:我发给你一张加密的身份证,以后你只要出示这张卡片,我花点时间解密这张身份证,我就知道你是不是自己人。 

广义的session

大家常犯的一个误区,把Session概念、session技术、具体的Session实现方式这三者混淆了。

会话(Session)是一个客户与服务器之间的不中断的请求响应序列。对客户的每个请求,服务器能够识别出请求来自于同一个客户。当一个未知的客户向Web应用程序发送第一个请求时就开始了一个会话。当客户明确结束会话或服务器在一个预定义的时限内不从客户接受任何请求时,会话就结束了。当会话结束后,服务器就忘记了客户以及客户的请求。
http是无状态的,为了能够在http协议上保持住状态,比如用户是否登录、购物车等等就需要一种方法来把用户的一个个无状态http请求关联起来,这种技术就是session技术。
session的作用就是把一个个分离的http请求关联起来,只要能实现这个功能的方法,都是session的一种实现,狭义的session id方式就是其中之一。
  • 在Cookie里放个JSESSIONID,在服务器中存上状态,用户请求来了,根据JSESSIONID去服务器里查状态,这是Tomcat的实现方法。
  • 把所有状态都存在Cookie里,服务器给个签名防止伪造,每次请求来了,直接从Cookie里解密从而提取状态,这是JWT的实现方法。
  • 在Cookie里放个token,状态不存在中间件里,而是存在Redis里,这也是一种Session实现方法。

只要HTTP还是无状态的,只要保存状态还是刚需,Session的技术要求就不会消失,变化的只是它的实现方式。

不管是“session id”,还是所谓“token”(如 jwt),都是会话的一种实现方式。形式上“session id”和“token”都是“字符串”,这个“字符串”可以是任意的编码,本质上都是 credential(会话凭证)。

客户端保管方式

credential 由客户端保管,客户端怎么存放几乎不关服务器的事,浏览器,安卓 app,ios app,桌面应用等都是客户端

浏览器一般把 credential 放在cookie里,就像把曲奇饼(cookie)放在小罐子里,cookie 特殊的地方在于,浏览器会听服务器的话,比如服务器在设置cookie时指定了“http only”,那浏览器就不会允许 js 拿到

至于其他的客户端,想放哪放哪,直接存文件或存本地数据库都行,或者还有其他骚操作都行。

无论是session id还是token,确实都是“客户端记录,每次访问携带”,但 token 很容易设计为自包含的,也就是说,后端不需要记录什么东西,每次一个无状态请求,每次解密验证,每次当场得出合法 /非法的结论。这一切判断依据,除了固化在 CS 两端的一些逻辑之外,整个信息是自包含的。这才是真正的无状态。 
而 sessionid ,一般都是一段随机字符串,需要到后端去检索 id 的有效性。万一服务器重启导致内存里的 session 没了呢?万一 redis 服务器挂了呢? 

传输方式

最常见的说法是“session_id”放 cookie 里,“token”放自定义的headers 里。

但这不是必须的,本来就只是“字符串”而已,放哪都是可以的,何况 cookie 也在 headers 里。

也就是说 "session_id" 可以放在自定义的 headers 里,"token"也可以放在 cookie 里。

session放在cookie头信息的样子:COOKIE: PHPSESSID=xxxxx。

当然,jwt也可以放cookie,也可以自定义一个头信息例如:X-Token: xxxxx。

会话信息存放方式

一般来讲会话中包含有一定量的信息,最核心的就是会话 id ,还有其他的信息,比如user_id 之类的。不同的实现方案会把会话信息放在不同的地方。

如果 credential 里没有会话信息,那它就是“session id”,其他的会话信息由服务器保管,保管的地方则是各有各的法子,比如内存,数据库,redis,甚至本地文件。

如果 credential 里包含了会话信息,也就是所谓“token”,那服务器就不需要花地方保存了,不过相应的代价是网络流量会大一点。本来保存在服务器的信息保存在了 token 里,自然会大一点。另外根据不同的字符串编码,可能还要要花时间计算(比如 jwt)

有人说 token 可以减小服务器存储空间,但这可以不一定是好事,如果光是活跃的会话信息就大到几个g了,那活跃期的网络流量光是传个 token 就要占用几个g的带宽,何况其他的信息所占流量。如果实际峰值流量没那么大,也说明花掉的存储空间不值一提。至少存储空间不应该成为选择方案的理由。

控制力

基本上,服务器保管的会话信息越多,对会话的控制力就越高。

比如很普遍的一个情况,你要禁止一个用户同时登录多个浏览器,或同时登录多个客户端。

如果用“session id”的方式实现,你只需要在服务器端删掉该用户的其他会话,或让他过期即可,客户端单方面持有旧“session id”也没用。

如果用“token”的方式实现,由于你无法要求客户端删除他的 token ,所以无法仅仅依靠 token 来实现。可行的实现方案之一, token 里加时间戳,某个时间点以前的 token 全部失效。是不是很容易就实现了?然而这个失效的时间点,却需要依然服务器来记录,一旦你这么做了,其实就相当于把一部分会话信息保存在了服务器,同时,不同客户端保存各自的 token 里也有一部分会话信息。

实际项目中,很少会使用纯粹的 token 实现方案,即会话信息全部保存在 token 里,服务端不保存任何信息。就如上面所说,实现某些功能时,需要 token 和服务端分别保存用于校验的信息,才能对 token 进行校验,实现对 token 的控制。

综上

“session id”和“token”之间绝对没有高下之分,无非是取舍而已,空间还是时间,流量大还是小,控制力高还是低。

在各种 session 方案中,你会发现实现细节都不一样,flask session, django session, spring session, jwt 等等。但万变不离其宗, credential 的客户端保存方式,credential 的传输方式和会话信息的保存方式,都只是这几个流程的细节有改变而已,本质都是为了实现有状态的 http。

参考:
 



原文地址:https://www.cnblogs.com/xulan0922/p/13986354.html