为每个人签名和验证 JSON Web 令牌 (JWT) JSON Web 令牌 (JWT) 回顾 理解 JWT 的挑战 为什么我们不需要知道签名和验证的工作原理? JSON Web 令牌的剖析 Owl 签名的其余部分 JWT 加密段:重新审视 验证签名 JWT 签名和验证:总结 资源以及下一步是什么?

2025-06-07

为每个人签名并验证 JSON Web 令牌 (JWT)

JSON Web Token(JWT)回顾

理解 JWT 的挑战

为什么我们不需要知道签名和验证是如何工作的?

JSON Web Token 的剖析

其余的 猫头鹰签名

JWT 加密部分:回顾

验证签名

JWT 签名与验证:总结

资源和下一步是什么?

当我开始学习JSON Web Tokens时,有些东西很容易理解,有些概念感觉像是JWT 传说中的“隐藏秘密”。🧙‍♂️

本文旨在揭开 JSON Web 令牌签名和验证的神秘面纱,几乎不需要安全或加密知识。

注意:本文是我的一篇关于“人人皆可授权和身份验证”的文章的配套文章。建议你先阅读那篇文章。

JSON Web Token(JWT)回顾

总体来说,JWT 相当容易理解。关于 JWT 的信息可以从很多渠道获取,主要包括:

  • JSON Web Tokens(或 JWT)是一种紧凑的、URL 安全的方式,用于在双方(例如授权服务器和应用程序)之间传输数据。
  • JWT 格式由IETF规范RFC 7519定义由三个段组成有效负载加密段)
  • JWT在生成时使用密钥进行签名,然后在收到时使用密钥进行验证,以便我们可以验证它们在传输过程中未被修改

理解 JWT 的挑战

有个梗叫“如何画猫头鹰”,讲的是刚接触一个概念,然后发现缺少一些步骤,而你却被期望在不了解中间步骤的情况下就能得到最终结果。这个梗演示了“如何画猫头鹰”:

1.

对我来说,无法找到有关签署和验证JWT 的可用信息,就像缺少画猫头鹰的步骤一样。

我找到的大多数资源都让我陷入了深深的“兔子洞”——直到我的脑海里充斥着令人费解的专业术语、Alice 和 Bob(密码学示例中使用的占位符名称)以及复杂的数学知识。我没有学习更简单、更循序渐进的步骤来帮助我理解,反而感觉像是拿到了十幅更复杂、更完整的猫头鹰图画。

为什么我们不需要知道签名和验证是如何工作的?

这是为什么?为什么大多数 JWT 资源只是简单地说“然后你签名并验证”就没事了?

可以这样想:人类要想有效或熟练地使用工具,我们不需要了解工具组件的复杂性。

🚙 当你开车去杂货店的时候,你需要知道内燃机的工作原理吗?你不需要。

🔋 当你给笔记本电脑充电时,你需要知道锂离子电池中会发生哪些化学反应,从而在电路中产生电子流,进而储存和产生能量吗?不需要!

即使不精通这些,我们仍然可以成为优秀的驾驶员或优秀的计算机程序员。我们相信,制造商已经运用他们的专业知识、规范和标准,并尽职尽责地制造出有用的工具,让我们能够更高效地完成所需的工作。

这就是为什么您不需要知道签署和验证 JWT 的确切过程,以便有效地使用它们来验证和授权您的应用程序和 API。

好吧,你读这篇文章是因为你还想知道画猫头鹰的那些步骤。虽然你通常不应该自己签名和验证令牌(说真的,把这事留给专家——身份提供商和身份即服务平台!),但了解它的工作原理能让你更轻松地使用 JWT。😌

JSON Web Token 的剖析

我们在上一篇关于身份验证和授权的博客文章中深入介绍了 JWT 的结构,现在让我们做一个非常简短的回顾。

JSON Web Tokens 由三个 URL 安全字符串段组成,这些字符串段用句点连接.

报头段

第一个段是标头段

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9

标头段是一个 JSON 对象,包含签名算法和令牌类型。它经过base64Url编码(以文本形式表示的字节数据,对 URL 和文件名安全)。

解码后,它看起来像这样:

{
  "alg": "RS256",
  "typ": "JWT"
}
Enter fullscreen mode Exit fullscreen mode

有效载荷段

第二段是有效载荷段

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0

这是一个包含数据声明的 JSON 对象,数据声明是关于用户和身份验证事件的声明。这是 JWT 从一个实体传递到另一个实体的信息。数据声明可能如下所示:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}
Enter fullscreen mode Exit fullscreen mode

这也是base64Url经过编码的。

加密段

最后一段是加密段,或者说签名。JWT 经过签名,因此在传输过程中无法被修改。授权服务器签发令牌时,会使用密钥对其进行签名。

当客户端收到 ID 令牌时,客户端也会使用密钥验证签名。(如果使用了非对称签名算法,则签名和验证会使用不同的密钥;在这种情况下,只有授权服务器才拥有对令牌进行签名的权限。)

其余的 猫头鹰签名

这就是 猫头鹰JWT 签名/验证流程如下。让我们一步步来了解一下。

RS256 签名

在本文中,我假设使用 RS256 签名算法。RS256 是一种基于SHA-256的 RSA数字签名算法。RSA256 是一种非对称密钥加密算法,它使用一对密钥:一个公钥和一个私钥来加密和解密。在这种情况下,私钥由令牌颁发者(授权服务器)使用,而公钥由接收令牌的应用程序使用,用于验证令牌。

如果你觉得这部分内容充满专业术语,令人困惑,别担心!让我们把它分解成更小、更清晰的步骤。

JWT 加密部分:回顾

让我们探索一下加密段实际上是什么。

签名输入

首先,我们获取 JWT 的前两部分(头部和有效载荷)。实际操作起来,大致如下:

标头+有效载荷段

换句话说,这是base64Url编码的标头和base64Url编码的有效载荷,用句点连接.

base64 URL 编码的标头 + 有效载荷段

这就是我们所说的签名输入

哈希

然后,我们使用SHA-256 哈希算法对签名输入进行哈希处理。哈希算法将一个值转换为另一个值。哈希函数使用数学算法从现有值生成新值。

  • 哈希运算是不可逆的。一旦我们对输入进行了哈希运算,就无法再恢复到原始输入。
  • 对于相同的输入,散列总会产生相同的输出。
  • 没有两个不同的散列输入会产生相同的输出。

SHA-256 哈希签名输入

此时,我们有了标头和有效负载段的哈希值 - 我们可以将其与其他哈希值进行比较,但无法逆转返回到原始签名输入。

加密

接下来,我们对散列后的签名输入进行加密。与散列不同,加密是可逆的:我们可以解密加密结果(称为密文),从而解密原始输入(明文)。

在此步骤中,令牌发行者(授权服务器)使用私有加密密钥对散列签名输入进行加密,以生成输出(密文)。

注意:我之前提到过,此示例使用 RSA,这是一种非对称签名算法,使用一个密钥加密令牌,使用另一个密钥解密令牌。如果您想以通俗易懂、实用的方式了解更多关于此主题的信息,请在 YouTube 上观看 Computerphile 的“公钥密码学”视频

最终输出(散列、加密、编码的标头和有效负载)是JWT 的加密段(或签名)。

加密、散列签名输入

注意:如果您想更深入地了解 RSA 加密算法本身的细节,我推荐Eddie Woo的这些精彩 YouTube 视频:RSA 加密算法

就是这样。这就是 JSON Web Token 的签名。🎉

验证签名

好的,我们可以开始了解令牌是如何签名的了——但这只是故事的一半!签名令牌的全部目的是,以便接收令牌的任何人都可以验证此 JWT 包含未被篡改的数据。

应用程序如何验证 JWT?

我们正在做什么?

首先,让我们看看接收令牌的应用程序可以获得哪些信息。我们可以访问 JWT 本身:头部有效载荷签名(也就是加密段)。我们还可以访问公钥,正如其名称所示,公钥是可以免费向全世界公开的。

注意:公钥是如何提供的?JSON Web Key (JWK) RFC 7517定义了加密密钥的 JSON 表示规范。如果您使用授权服务器平台,则会提供公钥——并且通常会封装在可为您处理 JWT 验证的 SDK 或库中。您可以阅读这篇博客文章了解更多信息:RS256 和 JWK 入门指南

请记住,签名是经过加密和哈希处理的标头和有效负载。哈希处理不可逆,但加密可以解密(在本例中,使用公钥)。JWT 的验证在于能够有效地将收到的内容预期内容进行比较。

解码索赔

应用程序可以解码标头和有效负载以获取一些信息。回想一下,这两个段经过base64Url了编码,以确保 URL 安全。解码这些段并没有什么加密的神奇之处或安全性;事实上,您可以使用一个简单的在线 base64 解码工具来完成。解码后,我们可以轻松读取其中的信息。例如,我们可以解码标头段,查看 JWT 签名时所用的算法。

另一方面,签名的目的是验证其他段中的信息与授权服务器发送的信息相同,并且在此过程中没有被更改。

从解码后的头部我们可以看到:

{
  "alg": "RS256",
  "typ": "JWT"
}
Enter fullscreen mode Exit fullscreen mode

我们收到的令牌显示算法为 RS256。我们的应用程序应该配置为使用授权服务器(令牌颁发者)使用的算法。当我们读取 JWT 标头中的算法时,应该验证它是否符合我们配置的期望值。如果不匹配,我们应该直接拒绝该令牌。

再次哈希

如果令牌中的算法符合我们对 RS256 的预期,我们就知道需要生成标头和有效载荷段的 SHA-256 哈希值。这将再次生成签名输入哈希。请记住,哈希计算是不可逆的,但相同的输入始终会产生相同的输出。如果我们根据收到的标头和有效载荷生成哈希,它应该与签名中加密的标头+有效载荷哈希匹配。

因此,我们将对连接后的已编码标头和有效负载进行哈希处理。现在,我们在应用程序base64Url端获得了新计算的签名输入哈希值

解密

哈希签名输入也包含在签名中,但它已被授权服务器(令牌颁发者)使用私钥加密。应用程序拥有公钥,因此我们可以解密签名。解密完成后,我们就可以访问原始哈希值:即授权服务器在首次生成令牌时生成的哈希值。

比较哈希值

现在,我们可以将解密后的哈希值与计算出的哈希值进行比较。如果它们相同,则我们已验证 JWT 标头和有效负载段中的数据在授权服务器创建令牌和我们的应用程序收到令牌之间未被修改。🎊

+ 验证令牌声明

一旦我们验证了签名,就还有更多工作需要验证 JSON Web Token 的数据。有效载荷段中的声明应该被验证,因为它们包含有关令牌颁发者、令牌到期日期、令牌的目标受众、将令牌绑定到授权请求的信息等等。

这些数据为接收应用程序提供了签名验证本身无法提供的重要细节。例如,检查声明可以发现,一个技术上有效的令牌实际上是为其他应用程序或用户设计的、已经过期、来自与该应用程序无关的发行者等等。

JWT 签名与验证:总结

现在我们已经介绍了签署 JWT 和验证 JWT 签名。

JWT 加密段和验证

我希望您能够自信地理解 JWT 签名和验证的几个步骤:

猫头鹰与所有步骤

仍然需要重申的是,作为一名开发人员,您很可能永远不需要亲自实现这些流程。事实上,除非您的工程重点是安全和身份,否则您可能不应该这样做

Auth0OktaPing Identity身份平台可以为您完成所有这些工作:在授权服务器端颁发和签署令牌,并在应用程序或 API 端提供用于验证和令牌管理的 SDK 和库。


资源和下一步是什么?

正如我在开篇提到的,本文是《人人皆可授权和身份验证》的补充和补充,后者是一篇更全面的资源,涵盖了 OAuth、OpenID Connect、授权服务器、JSON Web Tokens、API 授权、带作用域的委托等内容的历史。如果您想进一步了解身份主题,请阅读这篇文章。

了解更多

为了创建一个易于理解的、广泛接受的 JWT 签名和验证介绍(这是我希望得到的介绍,我简化了那些非常丰富和复杂的主题。

🧠 要了解更多信息,请尝试从以下一些资源开始:

谢谢你!

如果您想聊天,我的推特账号是@KimMaida,我也会在一些会议和活动上发言——至少在新冠疫情之前是这样。希望有机会见到您,非常感谢您的阅读

文章来源:https://dev.to/kimmaida/signing-and-validating-json-web-tokens-jwt-for-everyone-25fb
PREV
如何使用 Gatsby 和 React Hooks 实现“黑暗模式”
NEXT
如何在技术会议上实现价值最大化(作为内向者)