JSON Web Token,简称 JWT ,是一个轻巧的开放规范,用于在客户端和服务端之间传输数据。它的内部编码使用的是 JSON 格式,故称 JSON Web Token。最初 JWT 是用于通过 URL 传输数据的场景,不过常常用于用户认证/鉴权。

JWT 组成

以下提到的组成部分都可通过 JWT.io 来进行实验。

Header(头部)用于存储描述 JWT 的基本信息,如类型 typ 和其采用的加密算法 alg

示例如下:

1
2
3
4
{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

Payload (载荷)顾名思义即使用者想要放入 JWT 的数据,也是 JSON 格式:

1
2
3
{
  "userId": "104061"
}

SIGNATURE

即签名算法,以 JWT.io 官网为例,签名算法为:

1
2
3
4
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  "secret"
)

即将前面的 Headerpayload 进行 BASE64 编码以后用 . 连接在一起,然后用 secret 作为密钥,使用 HS256 对称加密算法进行加密。

结果为完整的编码后的token:

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMDQwNjEifQ.ZhrjY9uZ_HnE6GUxdTbMTbC83PHuDylnuClEmqV7SiQ

看图中代码的颜色即可看出各个部分

JWT优点

payload 无需密钥即可解码出 payload 的数据。这既是优点也是缺点:优点在于客户端无需传递密钥即可解密出 payload 的内容,缺点是载荷中 不能 存储用户的敏感信息。

安全性方面,假设有中间人对载荷的内容进行修改(但是没有正确的密钥),签名后的 JWT 是无法通过服务端的校验的。

JWT实际应用

通过URL鉴权

最常见的场景是营销邮件的退订功能(无需登录状态)。在不用 JWT 的情况下,需要一个 email adderss 和 token / session。如以下url:

http://www.xxx.com/unsubscribe?email=xxx@xxx.com&token=xxxxxx

这样有个缺点就是使用的 token 必须存储在服务器中,假如使用 JWT 就可避免这个问题。

http://www.xxx.com/unsubscribe?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMDQwNjEifQ.ZhrjY9uZ_HnE6GUxdTbMTbC83PHuDylnuClEmqV7SiQ

服务端只需从 jwt 中解码出必要的用户信息即可,也可防止用户信息被伪造,也 无须服务器存储状态

用户认证系统

以下使用 Express.js 为例,简单描述一下 JWT 的用法。

  1. 用户登录,验证帐号密码后生成一个 JWT token;
  2. 设置 Cookies: Set-Cookies:jwt=xxx; max-age=xxx
  3. 在要求登录的接口处验证 JWT 的有效性。

强制绑定手机

同认证系统,只不过在 payload 中多加 mobile 字段。客户端使用 jwt 解码 payload,看是否存在 mobile 字段,如果不存在,则强制跳转至绑定手机的页面。