【071】JWT 简介

这篇文章翻译自 JWT 官网: https://jwt.io/introduction/

什么是 JWT (JSON 网络令牌)?

JWT(JSON 网络令牌)是一个开源的标准(RFC 7519)。这个标准定义了一个简洁并且自包含的方法,以便在系统各个部分之间安全地传送JSON对象格式的信息。因为通过JWT传递的信息是被数字签名过的,所以是可以被证实和信任的。我们可以使用单一密钥来加密 JWT 的签名,比如 HMAC 算法;也可以使用 RSA 的公私密钥对来加密 JWT 的签名。

让我们更深入地来解释一下这个定义中的一些概念:

  • 简洁:因为 JWT 体积比较小,我们可以通过 URL,POST参数或者 HTTP 报头来发送 JWT。另外,较小的体积意味着发送速度比较快。

  • 自包含:装载的数据包含和用户相关的所有需要的信息,避免了额外再查询一次数据库的需求。

你应该什么时候使用 JWT ?

这里有一些适合使用 JWT 的场景:

  • 身份验证:这是 JWT 最常用的场景。一旦用户登录进系统,每一个后继的请求都会包含 JWT。系统允许用户访问那些令牌有权限的路由,服务和资源。单点登录是一个在当代广泛使用 JWT 的特性,这是因为下面两点原因:其一是 JWT 的系统开销很小;其二是 JWT 能够轻而易举地应用到跨域的场景中。

  • 信息交换:JWT 是一种在系统各个部分之间安全地传送信息的方法。这是因为只要 JWT 可以被数字签名,比如使用公私密钥对,你就可以信任 JWT 中包含的发送者身份信息。除此之外,当签名在计算的时候,使用了 JWT 的头部部分和负载部分,你也可以验证信息的内容有没有被篡改过。

JWT 的结构是什么样子的?

JWT 由三部分组成,三个部分之间用英语句号(.)分割。这三个部分分别是:

  • 头部
  • 负载
  • 签名

因此,一个典型的 JWT 令牌看起来像下面这个样子:

xxxx.yyyy.zzzz

让我们接下来分析不同的部分。

头部

一个典型的头部由两部分组成。第一部分是令牌的类型,一般是JWT。第二部分是用到的哈希算法,比如像 HMAC、SHA256 或 RSA。比如:

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

然后,这个 JSON 会以 Base64Url 进行编码,并作为 JWT 的第一部分。

负载

令牌的第二部分是负载,负载包含声明。声明是与一个实体(通常是用户)和额外的元信息相关的语句。有三种类型的声明:保留型声明、公开型声明和私有型声明。

  • 私有型声明:有一套非强制但推荐的预定义声明,来为使用者提供一系列有用的,可以互操作的声明。它们中的一些是:iss(发行者)、exp(过期时间)、sub(主题)、aud(观众)和其它的。
    注意声明的名称只有三个字符的长度,这是由于 JWT 被普遍认为应当是简洁的。

  • 公开型声明:这些声明可以被 JWT 的使用者随意地定义。但是为了避免冲突,它们应该在 “JSON 网络令牌网络分配号码授权注册中心“(IANA JSON Web Token Registry)进行定义。或者定义的时候像 URI 一样包含一个防止冲突的命名空间。

  • 私有型声明:这种类型是自定义的声明。这种声明被创建出来,用来在系统中各个允许使用私有型声明的部分共享信息。

一个负载的例子可以是这样的:

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

然后负载就按照 Base64Url 编码,并组成 JWT 的第二部分。

签名

为了生成签名部分,你不得不取得编码后的头部、编码后的负载、一个密钥和头部中指定的算法,然后生成签名。

举个例子,如果你想使用 HMAC SHA256 算法,签名将会按照下面的方式被创建出来:

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

签名用来证实 JWT 的发送者就是 JWT 中所写的那样。并且签名还用来确保信息在传送途中没有被篡改。

把所有部分组合到一起

输出结果是三个被英文句号分割的 Base64 字符串。这些字符串可以容易地在 HTML 和 HTTP 环境中传送的;同时简洁程度好于类似 SAML 那种基于 XML 的标准。

下面展示了一个完整的 JWT。它包含了前面提到的编码后的头部和负载,并且它用了一个密钥来生成签名。

这里写图片描述

如果你想要试试 JWT,并且把上面提到的概念付诸实践,你可以使用 jwt.io Debugger 来解码、验证和生成 JWT。

这里写图片描述

JWT 是怎么运行的?

在身份验证过程中,当用户使用凭证成功登录的时候,服务器会把一个 JWT 令牌返回给客户端并且 JWT 令牌一定在客户端本地存储(通常是 local storage,但是 cookie 也是可以的),而不是采用传统方法在服务器创建一个 session 并返回给客户端(浏览器)一个 cookie。

用户无论何时想要访问一个受保护的路由或资源,浏览器(译者注:除了浏览器,也可以是其他软件,比如手机 APP。)都要发送 JWT,通常是在使用 Bearer 模式的 Authorization 报头中。报头的内容应该看起来像下面这样:

Authorization: Bearer <token>

因为用户状态从来没有保存到服务器的内存中,所以这是一个无状态的身份验证机制。服务器的受保护的路由将会在 Authorization 报头中检查是否存在一个有效的 JWT 令牌。如果存在有效的令牌,用户将会被允许访问受保护的资源。因为 JWT 是自包含的,所有的必要信息都在 JWT 里,所以减少了多次查询数据库的需求。

这套机制允许你完全依赖无状态的数据 API,甚至允许你向下游服务发起请求。你的 API 用哪个域名都没有关系。因为基于 JWT 的身份验证机制不使用 cookie,所以跨域资源共享(CORS)不会成为一个难题。

下面的图表展现了这套流程:
这里写图片描述

我们为什么要使用 JWT ?

当把 JSON 网络令牌(JWT)、简单网络令牌(SWT)和安全断言标记语言令牌(SAML)放在一起比较的时候,让我们谈谈 JWT 的好处。

因为 JSON 没有 XML 那么冗长,所以当 JSON 被转成编码的时候,体积也会更小些。这使得 JWT 比 SAML 更加简洁。在 HTML 和 HTTP 环境下,这些优点促使 JWT 变成一个很好的选择。

在安全方面,SWT 只能对数据签名进行对称加密。SWT 使用了 HMAC 算法,并通过一个共享的密钥来进行对称加密。然而,JWT 和 SAML 令牌能够以 X.509 认证的形式,使用一对公私密钥来对签名进行加密。和给JSON生成数字签名的简便性相比,给XML生成数字签名,既要生成XML格式的数字签名,又要不引入晦涩难懂的安全漏洞是非常困难的。

因为 JSON 可以直接映射成对象,所以 JSON 语法分析器在绝大多数编程语言中都很常用。相反地,XML 没有一个天生的文档到对象的映射。这一点使得应用 JWT 比 应用 SAML 更加简单。

关于用途,JWT 被广泛使用在互联网化的地方。这一点突出了 JWT 在多平台客户端(特别是移动设备)处理上的易用性。

比较一下编码后的 JWT 和编码后的 SAML 的长度

看上面的图,比较一下编码后的 JWT 和编码后的 SAML 的长度。

如果你想要阅读更多关于 JWT 的内容,甚至想在你的应用中使用 JWT 实现身份验证,请浏览 Auth0 网站上的 JWT 登录页面

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值