简体中文
  • jwt
  • auth
  • 身份验证
  • 身份
  • api
  • openid
  • oauth

什么是 JSON Web Token (JWT)?

5分钟内清晰地理解 JSON Web Token (JWT)基础知识。

Gao
Gao
Founder

JSON Web Token (JWT) 在现代网络应用和开放标准如 OpenID Connect 中得到了广泛使用,支持身份验证和授权。虽然官方的 RFC 7519 提供了必要的参考信息,但对初学者来说理解起来会有所挑战。在本文中,我们将专注于 JWT 的核心概念,并结合案例,用通俗易懂的语言来阐释它们。

我们为什么需要 JWT?

如今,使用 JSON 在两个实体之间交换数据已经非常常见。我们可以考虑一个代表用户的 JSON 对象:

sub 是 "subject" 的缩写,它在 OpenID Connect 中作为标准声明来代表用户标识符(用户 ID)。

我们如何保证这个 JSON 对象的完整性呢?也就是说,如何确保数据在传输过程中不被篡改?一个常见的解决方案是使用数字签名。例如,我们可以使用公钥加密:服务器使用私钥签署 JSON 对象,客户端可以使用服务器的公钥来验证签名。

简单来说,JWT 提供了一种标准化的方式来表示 JSON 对象及其签名。

JWT 的格式

由于有许多方式可以创建数字签名,因此有必要指定用于 JWT 签名的算法。这可以通过构造 JSON 对象来完成:

alg 是 "algorithm" 的缩写,typ 是 "type" 的缩写。

通常,typ 被设置为大写的 JWT 。对于我们的例子,algHS256 ,它代表了 HMAC-SHA256(我们稍后会解释它),并且表示我们正在使用这个算法来创建签名。

到目前为止,我们已经拥有了 JWT 中所有的成分:

  • Header JSON:算法和类型
  • Payload JSON:实际数据
  • Signature:包含 header 和 payload 的签名

然而,空格和换行等某些字符不对网络传输友好。因此,header 和 payload 需要进行Base64URL-编码。典型的 JWT 看起来是这样的:

. 起到了分隔的作用。

让我们把所有的东西放在一起,创建一个 JWT:

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

Base64URL 编码:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Payload

JSON:{"sub":"foo","name":"John Doe"}

Base64URL编码:eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ

Signature

在 HMAC-SHA256 中,签名是由一个秘密创建的:

例如,当 secret 为 some-great-secret 时,签名变为:XM-XSs2Lmp76IcTQ7tVdFcZzN4W_WcoKMNANp925Q9g

JWT

最后的 JWT 是:

这个有效的 JWT 可以由任何拥有 secret 的方验证。

选择签名算法

如前所述,有许多算法可以创建数字签名。我们以 HS256 为例,但它可能不够强大,因为 secret 必须在双方(例如客户端和服务器)之间共享。

在实际场景中,客户端可能包括无法保证 secret 安全的公共应用,例如 React 应用。因此,首选的做法是使用公钥加密(即非对称加密)来签署 JWT。让我们从最流行的算法:RSA 开始。

RSA

RSA 是一种非对称算法,它使用一对密钥:公钥和私钥。公钥用于验证签名,私钥用于签名。

RSA 的 header JSON 如下所示:

RS256 代表 RSA-SHA256,这意味着签名是由 RSA 算法和 SHA256 哈希函数生成的。你也可以使用 RS384RS512 来分别用 SHA384 和 SHA512 哈希函数创建签名。

签名是用私钥创建的:

再次展示,我们可以将这些部分组合起来创建一个 JWT,最后的 JWT 看起来是这样的:

现在,客户端可以在不知道私钥的情况下验证签名。

ECDSA

虽然 RSA 得到了广泛的使用,但它的签名体积较大,有时会超过 header 和 payload 的总大小。椭圆曲线数字签名算法(ECDSA)是另一种非对称算法,它可以创建更小的签名,并且更加高效。

为了为 ECDSA 生成私钥,我们需要选择一条曲线。这超出了本文的范围,但你可以在这里找到更多相关信息。

ECDSA 的 header JSON 如下所示:

ES256 代表 ECDSA-SHA256,这意味着签名是由 ECDSA 算法和 SHA256 哈希函数生成的。你也可以使用 ES384ES512 来分别用 SHA384 和 SHA512 哈希函数创建签名。

签名是用私钥创建的:

最后的 JWT 保持与 RSA 相同的结构,但其签名明显更短:

验证 JWT

验证 JWT 简单到可以看作是创建 JWT 的反向过程:

  1. 使用 . 分隔符将 JWT 分为三个部分(header,payload,签名)。
  2. 使用 Base64URL 对 header 和 payload 进行解码。
  3. 使用 header 中指定的算法和公钥(适用于非对称算法)来验证签名。

有许多库可以帮助进行 JWT 验证,例如针对 Node.js 和 web 浏览器的 jose

结论

在本文中,我们简要解释了 JWT 的核心概念,并概述了如何创建和验证它。还有许多细节我们没有探讨,我们将在未来的文章中介绍它们。

Logto 利用像 JWT 和 OpenID Connect 这样的开放标准来保护你的应用程序和 API,并为每个开发者简化工作流。如果你有兴趣,你可以免费试用(无需信用卡)。