最近在一个新项目中,要做鉴权的事宜,于是 Token 的话题又被拿了出来,JWT 是一个很火的名字,但事实上,并没有人很了解这个东西,于是我准备自己来解释下。
⭐️ ️️如何传递用户的安全信息
HTTP 的无状态特性
在 Web 应用中,经常要处理的一类问题是,验证。如何记住当前是哪一个用户是一件很麻烦的事情。
这是因为 HTTP 协议是短连接,每次请求都是无状态的,这使得每次客户端和服务器都需要在会话时,带上 我是谁
这个信息。
用户安全信息常用有两种方式:
- Cookie
- Token
🔅 HTTP Cookie
HTTP 协议 中有关于 Cookie 的定义。人们可以通过将数据写入 cookie ,每次 HTTP 请求都带上这段信息的方式来进行信息传递。
用户安全信息不属于业务的部分,被放在 Cookie 里再适合不过了。
通常,在 Cookie 里记录着用户的安全信息,这些信息包括 token,或者一些用户的数据,以减少服务端每次查询的压力。
但浏览器为了安全考虑,通常对 Cookie 做了严格的限制,像不得跨域携带等,在 API 时代,Cookie 更加的不方便使用。
🔅 HTTP Request
于是,一个解题的新思路就来了,能不能把数据放在 HTTP 的请求头中,像 Header 或 QueryString 中。
我们把这种方式叫做 Web Token。
好处显而易见,不再有跨域的麻烦,而且是 HTTP 标准,处理起来也很方便。
⭐️ Web Tokens
我们定义了 Web Token 在请求体中的位置,但 Web Token 的格式,还没有做要求。理论上一个请求体上的内容,如果仅是自己在用的话,怎么写都可以,但当各方站点需要一起通讯的话,或者为了方便交流的原因,也会形成一个共用标准的。
于是就有以下几种常见标准:
- JSON Web Tokens (JWT)
- Simple Web Tokens (SWT)
- Security Assertion Markup Language Tokens (SAML)
对比
SWT 定义了文本的格式,有几个字段的标准,最终生成的是这些字符串的 base64
而 SAML 则是使用 XML 格式
JWT 则使用 JSON,除此之外,JWT 还定义了一些字段的要求
🔅 SWT
SWT 只在 MSDN 和 JWT 的说明文档上见到,可见使用不是特别的广泛。
这是它的定义部分:
1 | Issuer = issuer.example.com |
Base64 后的结果
1 | N4QeKa3c062VBjnVK6fb+rnwURkcwGXh7EoNK34n0uM= |
🔅 SAML 2.0
除了 XML 数据格式外,还定义了以下标准字段:
- saml:Issuer
- ds:Signature
- saml:Subject
- saml:Conditions
- saml:AuthnStatement
- saml:AttributeStatement
可以看下 Wiki 上的定义内容,特点就是冗长,因为在长了,这里也就不再复制了。
🔅 JWT
JWT 是目前最火的 Web Token 协议,已经被加入 RFC 中了。这得益于 JSON 的优点,广泛的平台和比较轻巧的格式。
简单的说,它使用了 JSON 格式,由三个部分组成:
- Header
- Payload
- Signature
- Header
头部由两部分信息:
- 声明类型,这里是 JWT
- 声明加密的算法 通常直接使用 HMAC/SHA256
1 | { |
将这部分值进行 Base64 得到 JWT 第一部分: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
- Payload
Payload 是存放信息的地方,它有也一些标准字段的定义,但都不是强制的。
1 | { |
最后将这部分值进行 Base64 得到 JWT 第二部分:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
- Signature
它由前两部分的 Base64 值合在一起,再由 Header 中的加密方式生成这一部分:TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
最终,就变成这样的一个字符串:
很小,这方便了它的传输,可以放在 Header 里,也可以放在 QueryString 中。
⭐️ 后续
这里我们介绍了如何传递用户安全数据的方式,然后对 Web Token 的几种常见标准进行了介绍。
作为主流当红的 JWT,接下来我们会再花笔墨去重点介绍下。