官网:https://jwt.io/
峰哥链接:https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
一. JWT理论介绍
客户端登录,服务器认证后,生成一个json对象,后续通过json进行通信。
什么是jwt
JWT只是缩写,全拼则是 JSON Web Tokens ,是目前流行的跨域认证解决方案,一种客户端保存登录状态的解决方案,一种基于JSON的、用于在网络上声明身份的令牌(token)。
JWT结构:
一个token分为3部分:
- 头部(header) - 生成token的元数据,比如加密算法、数据类型
- 载荷(payload) - 保存的真正的数据
- 签名(signature)
3个部分用"."分隔,如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
header:
JWT的头部分是一个JSON对象,描述元数据,通常是:
json
{
"typ": "JWT",
"alg": "HS256"
}
- typ 为声明类型,指定 "JWT"
- alg 为加密的算法,默认是 "HS256"
payload:
载荷(payload)是数据的载体,用来存放实际需要传递的数据信息,也是一个JSON对象。
JWT官方推荐字段:
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
也可以使用自定义字段,如:
js
{
"username": "vist",
"role": "admin"
}
signature:
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以作为token返回给用户了。
客户端得到的签名:
js
header.payload.signature
jwt+rsa非对称加密
token是识别客户端身份的唯一标示,如果加密不够严密,被人伪造那就完蛋了。
采用何种方式加密才是安全可靠的呢?
我们将采用JWT + RSA非对称加密
补充:
Base64URL:
加密/解密 工具:http://www.metools.info/code/c81.html
使用方式:
- /api?token=xxx
- cookie 写入token
- storage写入token,请求头添加:Authorization: Bearer <token>
二. 通过JWT生成token
js
// 在服务端生成token
router.post('login', async ctx => {
const { userName, userPwd } = ctx.request.body;
const res = await User.findOne({
userName,
userPwd
})
// 第一个参数:需要保存的数据
// 第二个参数:签名使用的秘密
// 第三个参数:额外配置
const token = jwt.sign({
data: res
}, 'test', { expiresIn: 30 })
const data = res._doc;
if (res) {
data.token = token;
ctx.body = utils.success(data);
} else {
}
})
js
// 在服务端认证token
router.post('getData', async ctx => {
const token = ctx.request.headers.authorization.split(' ')[1];
const payload = jwt.verify(token, 'test');
ctx.body = payload;
})