Cookie,Session和JWT
HTTP是无状态的协议,每次客户端和服务端会话完成时,服务端不会保存任何会话信息:每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,因此也无法知道上一次的请求发送者和这一次的发送者是不是同一个人。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态需要通过 cookie 或者 session 去实现。
Cookie
Cookie是存储在客户端的一小块数据,也就是存储在本地,cookie会在浏览器下次向同一域名(服务器)发送请求的时候携带在请求头上一起发送到服务器上。
- Cookie存储在本地
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKKvNh6D-1603093386454)(https://i.loli.net/2020/10/19/TnOM5aX7wgkUFuZ.png)]
- 请求头中的Cookie
Cookie是不能跨域的,Cookie会绑定单一的域名,其他域名没法使用,也就是说www.A.com的Cookie没法在www.B.com中使用。Cookie可以设置在父域名,子域名的都能共享Cookie,比如:buy.A.com和look.A.com都是A.com下的,他们两个可以共享Cookie
Session
Session是另一种记录服务器和客户端会话状态的机制,Session是基于Cookie实现的,而Session是存储在服务器里,Cookie是存储在客户端中,但是服务器生成 的SessionID是存储到了Cookie中。
Session的认证过程:
- 用户第一次请求服务器的时候,服务器根据用户提交的信息,创建对应的Session,并通过该Session生成SessionID返回给浏览器。
- 浏览器收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名。
- 当用户第二次请求服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。
JWT(Json Web Token)
JWT由三个部分组成:
* Header(头部)
* Payload(负载)
* Signature(签名)
- 头部是描述JWT的元数据
Header:
{
"alg":"HS256",
"typ":"JWT"
}
alg表示签名用的加密算法,默认是HS256,type表示token的类型,统一写为JWT
- 负载是用来存放一些数据,但是JWT 默认是不加密的,任何人都可以读到,所以不存放私密数据,一般存放用户名等数据。如下
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
--------
{
"exp":"2334234234",
"iat":"1223412412",
"iss":"tcl",
}
-
签名是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HS256),按照下面的公式产生签名。
Base64URLEncode(Header)+"."+Base64URLEncode(Payload)+".",secret
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,就可以返回给用户
Header.Payload.Signature
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qKdORvfK-1603093386466)(https://i.loli.net/2020/10/19/3bIoRDri9CkTFzQ.png)]
使用方式:
客户端收到Token后,可以存储在Cookie里面,或者存在localStorage,此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization
字段里面。
Authorization: Bearer <token>//注意前面还有个Bearer
验证方式:
服务器收到请求发来的Token后,会把Token的前两个部分。即:“Header.Payload”,通过头部声明的加密算法,使用密钥进行加密得到一个签名,将该签名和Token中的签名进行比较,如果相等则Token有效
JWT和Session的区别
-
Session是存储在服务端的,不利用扩展,对于分布式和集群不用好,除非将Session持久化或者存储在Redis中
-
JWT是无状态的,不需要存储,只需要在服务器中计算下是否是合法的Token即可,用时间换空间,有利于扩展
-
Session不存储信息,JWT能存储一些常用信息,减少数据库的访问
-
由于WT是默认不加密的,JWT的payload是使用BASE64URL编码的,并没有加密,因此JWT中不能存储敏感数据。而session的信息是存在服务端的,相对来说更安全。
-
JWT一旦签发,在有效期内都是有效的,例如我们在payload中存储了一些信息,当信息需要更新时,则重新签发一个JWT,但是由于旧的JWT还没过期,拿着这个旧的JWT依旧可以登录,那登录后服务端从JWT中拿到的信息就是过时的。
-
JWT的续签