Web Token

最近在一个新项目中,要做鉴权的事宜,于是 Token 的话题又被拿了出来,JWT 是一个很火的名字,但事实上,并没有人很了解这个东西,于是我准备自己来解释下。


⭐️ ️️如何传递用户的安全信息

HTTP 的无状态特性

在 Web 应用中,经常要处理的一类问题是,验证。如何记住当前是哪一个用户是一件很麻烦的事情。

这是因为 HTTP 协议是短连接,每次请求都是无状态的,这使得每次客户端和服务器都需要在会话时,带上 我是谁 这个信息。

用户安全信息常用有两种方式:

  • Cookie
  • Token

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
2
3
4
Issuer = issuer.example.com
ExpiresOn = 1/1/2010, Midnight
com.example.group = gold
over18 = true

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

头部由两部分信息:

  • 声明类型,这里是 JWT
  • 声明加密的算法 通常直接使用 HMAC/SHA256
1
2
3
4
{
"alg": "HS256",
"typ": "JWT"
}

将这部分值进行 Base64 得到 JWT 第一部分: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

- Payload

Payload 是存放信息的地方,它有也一些标准字段的定义,但都不是强制的。

1
2
3
4
5
{
"id": "1234567890",
"name": "John Doe",
"admin": true
}

最后将这部分值进行 Base64 得到 JWT 第二部分:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

- Signature

它由前两部分的 Base64 值合在一起,再由 Header 中的加密方式生成这一部分:TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

最终,就变成这样的一个字符串:

很小,这方便了它的传输,可以放在 Header 里,也可以放在 QueryString 中。


⭐️ 后续

这里我们介绍了如何传递用户安全数据的方式,然后对 Web Token 的几种常见标准进行了介绍。

作为主流当红的 JWT,接下来我们会再花笔墨去重点介绍下。