什么是JWT
JWT即 JSON Web Token,是一种认证协议,遵循RFC7519标准,一般用来校验请求的身份信息和身份权限。
JWT的应用流程
a. 用户使用账号、密码登录应用,登录的请求发送到服务端。
b. 服务端进行用户验证,然后创建JWT字符串返回给客户端。
c. 客户端在每次请求接口时,都在请求头带上JWT。
d. 最后服务端验证JWT合法性,如果合法则继续调用应用接口返回结果。
JWT的数据结构
JWT生成的token由header、payload、signature三部分组成,这三个部分用小数点“.”分隔开。
JWT示例
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
header,也就是头部信息,是描述这个token基本信息,是一个json格式:
{ "alg":"HS256", "typ":"JWT" }
alg代表的是后面signature签名部分的生成加密算法。
typ表示该token是JWT类型。
payload,就是你的那些用户数据啦,也是一个json格式。不过jwt不建议将敏感数据放进里面,因为规范里,payload和header一样,仅仅只是做一次base64编码后显示在token上。另外还有七个字段供选择:
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT的ID用于表示该JWT
以上七个为可选字段。
{ "sub": "富录博客",//默认字段 "name": "DGF",//自定义字段 }
signature,是这个token的签名,通常情况下是将前面的header和payload加上一个你自己定义的私钥字符串通过指定的算法生成的哈希值,以确保数据不会被篡改。
签名公式
HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)
注意JWT每部分的作用,在服务端接收到客户端发送过来的JWT token之后:
header和payload可以直接利用base64解码出原文,从header中获取哈希签名的算法,从payload中获取有效数据
signature由于使用了不可逆的加密算法,无法解码出原文,它的作用是校验token有没有被篡改。服务端获取header中的加密算法之后,利用该算法加上secretKey对header、payload进行加密,比对加密后的数据和客户端发送过来的是否一致。注意secretKey只能保存在服务端,而且对于不同的加密算法其含义有所不同,一般对于MD5类型的摘要加密算法,secretKey实际上代表的是盐值
JWT的优点
1. json格式的通用性强,所以JWT可以跨语言支持,比如Java、JavaScript、PHP、Node等都可以使用。
2. 可以利用Payload存储一些非敏感的信息。
3. 便于传输,JWT结构简单,字节占用小。
4. 不需要在服务端保存会话信息,易于应用的扩展。
JWT的缺点
1. 安全性没法保证,因此JWT里不能存储敏感数据。因为JWT的payload并没有加密,只是用Base64编码而已,所以如果有敏感信息的话容易泄露。
2. 无法中途废弃。因为一旦签发了一个JWT,在到期之前始终都是有效的,如果用户信息发生更新了,只能等旧的JWT过期后重新签发新的JWT。
3. 续签问题。当签发的JWT保存在客户端,客户端一直在操作页面,按道理应该一直为客户端续长有效时间,否则当JWT有效期到了就会导致用户需要重新登录。那么怎么为JWT续签呢?最简单粗暴就是每次签发新的JWT,但是由于过于暴力,会影响性能。如果要优雅一点,又要引入Redis解决,但是这又把无状态的JWT硬生生变成了有状态的,违背了初衷。