JWT使用与原理
一、简介
JSON Web令牌是一种开放的、行业标准的RFC 7519方法,用于安全地表示双方之间的声明。(来自官网翻译)
特点:
- 无状态:无需对会话进行额外的存储方案选择,适合分布式情景下使用
- 非对称加密:通过密钥进行加密前后比较,防止暴力破解
- 携带信息:通过负载携带部分常使用的信息,减少后端与DB的交互
二、使用流程
- 使用用户名与密码请求服务器
- 服务器验证用户信息
- 通过验证后,根据选定的加密方法、负载、密钥,产生一个token并返回给客户端
- 客户端接收到token后进行存储,并在后续的请求中携带该token
- 服务端在处理请求之前,对该token进行获取与验证,如果无误,继续处理请求;如果验证失败,则中止请求并返回特定信息
三、组成结构
通过英文句号.连接,由三部分组成:header(头部)、payload(负载)、signature(签证)
3.1 header(头部)
头部的原始信息类似下面形式的JSON:
{
"typ": 'JWT', //类型申明,
"alg": "HS256" //加密算法
}
上面的信息通过base64加密后,得到token中的第一个字符,即header
3.2 payload(负载)
负载也是由JSON信息通过base64加密得到的,此处可以添加自定义参数,如用户名、昵称等经常需要使用的信息(注意base64为对称加密,所以不要存放敏感信息于此)。
负载也有标准字段,常见的有如下:
- iss: 签发者
- iat: 签发时间(如无定义则为现在机器时间)
- exp: 过期时间,这个过期时间必须要大于签发时间
nodejs中的jsonwebtoken模块通过sign方法进行签名时,对于iat与exp的使用操作如下:
/**
* ./sign.js
*/
module.exports = function (payload, secretOrPrivateKey, options, callback) {
......
var timestamp = payload.iat || Math.floor(Date.now() / 1000); //iat无定义时,默认当前时间(秒)
......
if (typeof options.expiresIn !== 'undefined' && typeof payload === 'object') {
try {
payload.exp = timespan(options.expiresIn, timestamp);
}catch (err) {
return failure(err);
}
if (typeof payload.exp === 'undefined') {
return failure(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));
}
}
......
}
上面代码中的timespan函数引用同项目中的文件./lib/timespan.js :

可以看到,如果expiresIn如果为string类型的数字,如"60",则会当作秒数,与iat一起计算得到过期时间;如果expiresIn为Number类型,则会当作毫秒数(millisecond)计算过期时间。所以就有了官方Readme中的这句话:

3.3 签证(signature)
通过前面经过base64加密后形成的header与payload,以及密钥secret与编码方式(默认utf-8)进行非对称加密:

该处引用了jws包,其函数定义的地方如下:

jwsSign函数定义如下

由上述代码可以了解到,生成token的步骤是:
header和payload分别进行base64加密,将两个结果用点号.连接,得到securedInput- 通过定义
alg所对应的加密方法,利用密钥secretOrKey对securedInput进行非对称加密得到signature - 将
securedInput与signature再次通过点号.进行连接,即将header、payload、signature进行连接
四、验证原理
理论上,知道了token的生成方法,大致也就能反推到其验证的原理:
- 先将
header与payload通过非对称加密后,得到新的signature,与token中的原始signature相比较,如果不等,返回无效token - 如果相等,通过
base64解密,验证payload中的过期时间等信息,如果存在过期等异常情况,则也返回无效token(只是与前面无效token的返回信息不同罢了) - 如果一切正常,返回
payload等信息
为了证明我们猜想的正确性,还是通过观察jsonwebtoken源码来验证,这里就不一张一张的贴图了,将相关代码整合在一起的情况如下:

由上面的过程可以看到,验证的原理基本如猜想一样,验证后,返回解析后的payload等信息:

自此,token验证的流程完毕。

浙公网安备 33010602011771号