JWT小结

参考文章:什么是 JWT – JSON WEB TOKEN - 简书 (jianshu.com)

什么是JWT

JSON WEB TOKEN (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

token的构成

token由头部载荷签名三部分组成

头部(header)

1
2
3
4
5
6
7
{
'typ': 'JWT',//声明类型
'alg': 'HS256'//加密算法
}

//将头部进行base64加密后得到第一部分
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

载荷(playload)

载荷用于存放要保存的信息,如用户id、权限、过期时间等。

1
2
3
4
5
6
7
8
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

//将载荷进行base64加密后得到第二部分
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

签名(signature)

由三部分组成:加密后的头部header,加密后的载荷playload,加盐secret

1
2
3
4
5
6
7
// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

var signature = HMACSHA256(encodedString, 'secret');

//将加密后的头部和载荷结合起来,使用header中的加密算法进行加盐secret组合加密,得到第三部分
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

完整的token

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

如何验证token是否有效

获取token的前两部分,即加密后的头部和载荷

  • 检查token是否过期:将载荷解密后检查过期时间
  • 验证token是否未被篡改:再次使用加密后的头部和载荷生成签名,比较两次签名是否相同

token由谁颁发

用户在第一次登录后,用认证中心统一颁发token

token如何传输

客户端在进行请求的时候,将token存放在cookie中或者存放在请求头中

token续签

使用redis缓存

认证中心在颁发token的同时,在redis设置key为用户数据(用户id或其他特征信息)+客户端环境特征(IP、UA、网卡MAC等),最好再将key进行加密,如MD5,并设置对应的过期时间。

当收到token时,检查在redis是否过期:

  1. 如果过期则要求用户重新登录,
  2. 否则检查时间是否过半,如果没有则按照正常流程执行,
  3. 否则在redis中为key增加一半的有效时间

使用两个token

认证中心在颁发token的时候,颁发两个token,一个为正常使用token,一个为续签token,续签token过期时间比正常使用token时间长一倍。

  1. 当正常使用token未过期则按正常流程执行;
  2. 当正常使用token过期,续签token未过期,则重新签发两个新的token,延长其过期时间外其他信息完全相同;
  3. 如果续签token过期,则要求用户重新登录。

存在重复生成JWT的问题,解决办法:在认证中心设计一个Map,记录过去一段时间内(几秒钟)的原始JWT(key)和新生成的JWT(value),如果在一段时间发现同样的原始JWT,则返回相同的新JWT。