JSON Web Token 介绍

什么是 JSON Web Token

JSON Web Token (JWT) 是一个开放协议,通过简洁的 JSON 数据来达到安全交换数据的目的。

它是由逗号分隔的三个部分组成 - Header - Payload - Signature 所以看起来是这种形式 xxx.yyy.zzz

主要应用场景有身份验证(比如 native app 中)和数据交换。

Header 包含两部分:

  • token 类型,JWT
  • 签名算法,比如 HMAC SHA256RSA

一个 Header 示例:

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

Header 经过 Base64Url 编码后形成了 JWT token 中的第一部分。

Payload

Payload 包含声明(claims)数据,主要是 user 及其他额外的数据。声明分三种类型:

  • Registered claims:一些非强制但推荐的预设声明,能够提供有用互联的信息,譬如 iss (issuer), exp (expiration time), sub (subject), aud (audience) 等。注意到这些名称都是三个字符,因为 JWT 要求数据简练。
  • Public claims:具体使用时自由定义的部分。为防止冲突,应该定义在 IANA JSON Web Token Registry 或能够避免冲突的 URI 命名空间下。
  • Private claims:收发双方约定的私有声明,用来交换数据。

一个 Payload 示例:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Base64Url 编码后形成 JWT token 的第二部分。

备注:对于已经通过签名以防止信息被篡改的 token 中,Payload 和 Header 对任何人都是可见的,所以不要在其中放置私有信息,除非是信息本身已经加密过。

Signature

使用前面编码过的 Header, Payload,及 Header 中指定的签名算法,再加上一个 secret 便可以创建一个签名了 (signature)。

HMAC SHA256 算法为例,创建签名的方式会是下面的样子:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

该签名可用来保证信息传输过程中没有被篡改,同时,如果使用私有键值进行签名,还可以从 token 中解析出 JWT 的发送者是谁。

上面签名的输出是逗号分隔的三个 Base64-URL 字符串,可在 HTML 及 HTTP 环境下自由使用了。相比基于 XML 的方案,比如 SAML,JWT 可以说是很简练了。

上面的签名指定 secret 为 test 时的结果:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.sLYApJ08mxtW8hlSqE5zetiscOjzEt361dCUDtGsDxU

调试工具

通过 JWT 官网的 debugger 可在线生成和解析 token。

工作原理

用户登录后会得到一个 token,后续在请求受身份保护的资源时需要将该 token 带上。一般地,在请求头里通过 Authorization 字段以 Bearer 格式发送。

示例:

Authorization: Bearer <token>

Server 端检查 Header 中的 Authorization 字段以验证身份。

因为 JWT 通过 Header 传递身份,所以规避了跨域资源共享(CORS)的问题。

image

client-credentials-grant

来自 JWT 官网的图片展示了 Server 如何获取 token 并验证身份

  1. 客户端通过验证身份后拿到token
  2. 通过该token 再去请求其他受保护的资源

JWT 的优势

与 Simple Web Tokens (SWT) 和 Security Assertion Markup Language Tokens (SAML) 相比,JWT 会有一些优势。

相比 XML 方式,JWT 数据编码后更轻巧,这样便于 HTTP 传输和插入 HTML 中使用。

更加便捷的安全性。SWT 只能通过 HMAC 算法通过公用的 secret 来对称加密,而 JWT 和 SAML 可使用一对 公钥/私钥 进行 X.509  证书形式的签名。

JSON 格式在各编程语言中有广泛支持,而 XML 的解析则更加麻烦一些。

相关资源