前言
传统session登录问题
- session 保存在内存中,随着用户增多,服务端开销明显增大。如果是分布式保存在另外的redis等内存数据库中,假设这台服务器挂了,所有的登录业务都会出现问题。
- 安全: 因为session一般是基于Cookie的,客户端的Cookie有CSRF等安全风险。
JWT 长什么样
JWT有三段信息构成,并且使用.
进行连接。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZGFua3VuIiwiYWdlIjoyMCwiaWF0IjoxNTU5NjM4NzA1LCJleHAiOjE1NTk2NTMxMDV9.wAaIIlaN5GagC-dUO99uJJ4RgYuuRfMUcFbUkCuXtd4
header
{
"alg": "HS256", // 加密算法
"typ": "JWT" // 类型
}
然后使用base64 生成第一段
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 // 可以对称解密出来
payload
{
name:'heimanba',
age:20
}
然后对他进行base64加密,得到JWT第二部分
eyJuYW1lIjoiZGFua3VuIiwiYWdlIjoyMCwiaWF0IjoxNTU5NjM4NzA1LCJleHAiOjE1NTk2NTMxMDV9
signature
最后一部分是签名认证信息,由三部分组成
- header(base64后)
- payload(base64后)
- secret
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret'); // wAaIIlaN5GagC-dUO99uJJ4RgYuuRfMUcFbUkCuXtd4
最后将这三部分使用 .
进行连接成完整字符串,构成最终JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZGFua3VuIiwiYWdlIjoyMCwiaWF0IjoxNTU5NjM4NzA1LCJleHAiOjE1NTk2NTMxMDV9.wAaIIlaN5GagC-dUO99uJJ4RgYuuRfMUcFbUkCuXtd4
使用 jsonwebtoken
模块加密
jwt.sign(payload, secret, { expiresIn: '4h' });
使用
客户端一般在请求头加上 Authorization
,并且标注Bearer
headers: {
Authorization: `Bearer ${token}`
}
验证
使用 jsonwebtoken
模块验证
jwt.verify(token.replace(/^Bearer\s+/,''), secret);
token 刷新
Access token 时效问题 :
如果access token 时间太长,那么安全性会比较差。这里我们提出refresh token概念。access token的时间一般比较短(10分钟),refresh token时间可以比较长些比如1个礼拜。
用户首先登录获取access token 以及refresh token。如果access token过期则访问刷新接口,携带refresh token换取access token。再返回需要信息。