JWT究竟是什么呢?

译者按:如果你还在使用 session 验证用户的话,是时候了解一下 JWT 了!

本文采用意译,版权归原作者所有

小编推荐:Fundebug专注于 JavaScript、微信小程序、微信小游戏,Node.js 和 Java 线上 bug 实时监控。真的是一个很好用的 bug 监控服务,众多大佬公司都在使用。

JWT(JSON Web Token)究竟是什么呢?它有什么用?这篇文章将为你揭开谜底。

首先,我们不妨看一下IETF(Internet Engineering Task Force)对 JWT 的权威定义

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.

啊!什么鬼?! 水平有限,这样的定义我就不翻译了…

简单地说,JWT 是一个字符串,我们在发起网络请求时,将其放在 header 或者 url 中,这样可以保证传递的数据被篡改时能被我们发现,保证安全性。

示例 xxxxx.yyyyy.zzzzz 即为 JWT:

http://www.example.com/private/?token=xxxxx.yyyyy.zzzzz

小伙伴应该注意到了,JWT 由 3 部分组成,使用两个点区分。如下:

header.payload.signature

那么,header, payload 和 signature 分别指的是什么呢?

header 所表示的 JSON 对象通常由 2 个部分组成:token 的类型,即”JWT”; token 所采用的 hash 算法,例如 HMAC SHA256 或者 RSA。

{
"alg": "HS256",
"typ": "JWT"
}

然后,这个 JSON 对象采用 Base64Url 编码变成字符串,作为 JWT 的第一部分。

var header = {
alg: "HS256",
typ: "JWT"
};

// 将JSON对象使用base64编码为字符串
var encoded_header = Buffer.from(JSON.stringify(header)).toString("base64");
console.log(encoded_header); // 打印: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

// 将base64编码的字符串解析为JSON对象
var decoded_header = JSON.parse(
Buffer.from(encoded_header, "base64").toString()
);
console.log(decoded_header); // 打印: { alg: 'HS256', typ: 'JWT' }

可知,header 只是进行了编码,而非加密,其过程是可逆的。

Payload

payload 为 JWT 的第二部分,其 JSON 对象包含一系列键值对(key/value)。其中,有些预定义键有特殊含义,比如 iat、exp 等,iat 表示 JWT 生成的实际,而 exp 代表 JWT 过期的时间。开发者可以使用其他非预定义的键用于传输数据。

{
"exp": "2100-01-01",
"message": "Hello, Fundebug!"
}

然后,这个 JSON 对象采用 Base64Url 编码变成字符串,作为 JWT 的第二部分。

var payload = {
exp: "2100-01-01",
message: "Hello, Fundebug!"
};

// 将JSON对象使用base64编码为字符串
var encoded_payload = Buffer.from(JSON.stringify(payload)).toString("base64");
console.log(encoded_payload); // 打印: eyJleHAiOiIyMTAwLTAxLTAxIiwibWVzc2FnZSI6IkhlbGxvLCBGdW5kZWJ1ZyEifQ==

// 将base64编码的字符串解析为JSON对象
var decoded_payload = JSON.parse(
Buffer.from(encoded_payload, "base64").toString()
);
console.log(decoded_payload); // 打印: { exp: '2100-01-01', message: 'Hello, Fundebug!' }

特别注意,payload 只是进行了编码,而非加密,其过程是可逆的。因此,JWT 绝不是用来进行加密通信的。

Signature

signatrue,即签名,是 JWT 的第三部分。它由编码的 header 和 payload,使用用户指定的密钥 secret,采用 header 中指定的哈希算法生成。Node.js 自带的Crypto可以来演示 signatrue 是如何生成的:

var header = {
alg: "HS256",
typ: "JWT"
};

// 使用base64编码header
var encoded_header = Buffer.from(JSON.stringify(header)).toString("base64");

var payload = {
exp: "2100-01-01",
message: "Hello, Fundebug!"
};

// 使用base64编码pyload
var encoded_payload = Buffer.from(JSON.stringify(payload)).toString("base64");

const crypto = require("crypto");
var secret = "$T697UaW6QTWsw}rrt%*P6)ia";

// 生成签名signature
var signature = crypto
.createHmac("sha256", secret)
.update(encoded_header + "." + encoded_payload)
.digest("base64");
console.log(signature); // 打印: JiOyrHVgyTTSts6mYQpChRHO7J2/hNU4dOYkgeLthKE=

signature 是根据 payload 生成的,两者是一一对应的,这样可以保证 payload 的数据不被篡改,除非密钥 secret 泄漏。

最终生成的 JWT 为:

var token = `${encoded_header}.${encoded_payload}.${signature}`;
console.log(token); // 打印: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIyMTAwLTAxLTAxIiwibWVzc2FnZSI6IkhlbGxvLCBGdW5kZWJ1ZyEifQ==.JiOyrHVgyTTSts6mYQpChRHO7J2/hNU4dOYkgeLthKE=

当收到 JWT 时,可以采用同样的算法和密钥生成签名 signature,如果一致,说明数据没有被篡改。

很重要一点在于,JWT 是用于验证而非加密,任何人即使没有密钥 secret,header 与 payload 中的数据都是可以获取的。

使用jwt.io,可以进行 JWT 的编码、解码和验证:



关于Fundebug

Fundebug专注于JavaScript、微信小程序、支付宝小程序线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了80亿+错误事件。欢迎大家免费试用

版权声明

转载时请注明作者 Fundebug以及本文地址:
https://blog.fundebug.com/2018/07/12/what-is-jwt/

您的用户遇到BUG了吗?

体验Demo 免费使用