JSON Web Token
首发于 个人博客
使用 JWT 开发过两个项目,其一是区块链轻钱包接口开发,另外一个项目是对接中国移动和某银行支付渠道。实现接口的授权和明文数据加密,确保客户端和服务器之间的数据安全传输,比较适合用在 HTTP 接口认证、数据加密传输的应用场景。
JSON Web Token (JWT) 是一种约定的开放标准 RFC7519 ,报文内容简洁且能够携带信息,方便安全地在客户端和服务器之间传输。加密之后的信息是可信任和可验证并能解密出明文,有两种方式加密:HMSC 算法(HS 256)、公私钥(RS256)
进一步解释 JWT 的两个特性
- 简洁(compact): 由于加密后的 jwt token 串比较小,所以在网络传输时有很大的优势。可以拼接在 URL 中、可以放在 POST 请求 body 中或者放在 HTTP 请求头中。在传输过程中能够高效快速。
- 携带信息(Self-contained): payload 包含用户必要的信息,减少服务端查询数据库次数。
JWT 使用场景
基本上有两种应用场景
- 验签 Authentication:验签是最普遍用到的场景。当一个用户首次登录之后,后续前端所有的请求都携带服务器生成的 jwt token 串和服务器交互。轻量且没有跨域的特性,从而非常适合做单点登录。
- 信息传输 Information Exchange:JWT 能够使用公私钥加密明文,服务端能够判断请求是否合法且能判断出是在与哪个账号进行交互。签名(Signature)能够计算出 header 和 payload,服务端能够判断密文是否被篡改。
JWT 的结构
JWT 有英文句号(.)
分隔开的三部分组成,分别是:
- Header
- Payload
- Signature
所以,完整的 JWT 结构为
xxxx.yyyy.zzzz
就这三部分,进一步分别讨论。
Header
Header 由两部分组成:token 类型,值为 JWT ;算法类型,值为 HS256 或 RS256,例如:
{
"alg": "HS256",
"typ": "JWT"
}
然后 JWT 通过 Base64Url 编码成 JWT 的第一部分
Payload
payload 包含了 claims ,其中 claims 大概有如下三种类型。
- Reserved claims:这是 JWT 预定义的 claims ,非必需但推荐在 payload 中添加这种类型的 claims 。常见的有 iss(issuer), exp (expiration time), sub(subject),aud (audience)...
- public claims:这些可以通过 JWTs 随意定义。但为了避免冲突,他们应该使用 IANA JSON Web Token Registry 定义或使用 URL 定义。
- Private claims:自定义的的 claims,通常是客户端和服务端之间协商好需要的数据。
payload 的一个例子:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
payload 的明文会被 Base64Url 编码为 JWT 的第二部分。
Signature
JWT 最后一部分是 Signature, 由第一部分和第二部分再加上指定的算法加密而得到。例如使用 SH 256 算法生成 signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
第三部分被用来验证客户端是谁,及确保密文没有被篡改。
总结
接口验签和明文加密,JWT 确实是一种不错的选择。现在开发 API 是比较常见的需求,对于后端开发者来说投入时间了解掌握 JWT 高收益的事儿。
在实际的开发过程中,官方及第三方开发者基本都开发出覆盖各种编程语言的 Libraries。接下来我打算用 Ruby 实现一个完整的 JWT 加密验签和解签的 Gem