简体中文
  • auth
  • authentication
  • oauth
  • oidc
  • identity

为什么在大多数 OAuth 2.0 服务中使用 JWT

本文解释了为什么 JWT 被广泛采用为 OAuth 2.0 中访问令牌的格式,强调了它的优点和局限性。

Yijun
Yijun
Developer

OAuth 2.0 如今被广泛使用。作为一个授权服务的核心框架,OAuth 2.0 的主要职责之一是为用户颁发访问令牌。我们注意到,市场上的许多 OAuth 服务提供商都以 JWT 格式颁发访问令牌。

在本文中,我们将介绍什么是 JWT 以及为什么它被广泛采用为 OAuth 2.0 发放的访问令牌的格式。

JWT 简介

JWT 代表 JSON Web Token,它在 RFC 7519 中定义如下:

JSON Web Token (JWT) 是一种紧凑的、URL 安全的方式,用于在两方之间表示要传递的声明。

这个定义清楚地表明JWT 是用于在不同方之间传递声明的令牌。

由于 JWT 在多个方之间传递,它们被签名以确保数据的完整性和真实性。

一个签名的 JWT 具有以下格式:

它由三个部分组成,以 . 分隔:header、payload 和 signature。

以下是一个实际的 JWT 示例:

你可以在 https://jwt.io 尝试解析它:

在 jwt.io 中解码 JWT

如图所示,JWT 的 header 部分包含有关所使用的签名算法和令牌类型的信息。payload 部分包含 JWT 所携带的声明,而 signature 用于验证 JWT 的完整性。

现在我们了解了什么是 JWT 以及其不同部分的含义,让我们继续解释为什么许多 OAuth 授权服务选择 JWT 作为他们的访问令牌。

使用 JWT 的好处

JWT 与传统的随机生成的字符串令牌之间的关键区别在于,JWT 可以携带信息,并可以通过解码进行验证。这些区别带来了两个显著优势:

  • 资源效率:JWT 可以携带有关用户或会话的信息,从而消除了频繁的数据库查询需求。这种效率可以减少服务的资源消耗。
  • 改善可用性和可扩展性:JWT 减少了对服务器端状态管理的依赖。这使得服务能够更加无状态,提升了它们的可用性和可扩展性。

使用传统的随机字符串令牌时,验证和认证的典型过程如下:

如图所示,当系统拥有众多用户和不同的资源服务器时,这会导致向授权服务器发出大量的令牌验证请求。

随着系统的增长,授权服务器容易成为瓶颈,对整体服务的可用性构成挑战。

然而,引入 JWT 后,验证过程变为:

由于 JWT 允许通过解码进行验证的特性,资源服务器可以验证 JWT 的完整性并从中提取用户信息,而无需与授权服务器进行交互(有关 JWT 解码和验证的详细信息,你可以参考 Logto 文档)。

JWT 的局限性

虽然 JWT 在现代软件架构中提供了显著的优势,但它们也存在需要考虑的限制。

容易被窃听的 payload

如前所述,JWT 由三部分组成:headerpayload,和 signature。 这些组成部分是如何生成的?让我们以前面的 JWT 为例,展示 JWT 的生成过程:

如上面的代码所示,JWT 的头部和内容部分只是简单地编码为 base64 字符串。

这意味着只要有人获取到令牌,他们就可以轻易解码 JWT 的 base64 字符串并访问其携带的信息。相反,伪造一个内容并用其替换原来的 JWT 内容也是相对容易的。

虽然 JWT 的内容可以相对容易地被伪造,但需要注意的是,JWT 的签名部分无法用伪造的内容替换,因为它需要秘密签名密钥。因此,没有正确的签名,JWT 无法通过验证。

所以在使用 JWT 时,需要记住以下几点:

  1. 始终使用 SSL:确保 JWT 信息在传输过程中不泄露,必须使用 SSL(Secure Sockets Layer)或其继任者 TLS(Transport Layer Security)来加密传输的数据。
  2. 避免存储敏感数据:不推荐在 JWT 内容中存储敏感数据。正如前所述,内容可以很容易地被解码,并且应该主要包含非敏感的、相关的声明。
  3. 验证 JWT:在依赖 JWT 所含信息之前,确保它已经通过验证,包括验证签名并检查令牌是否过期。这有助于防止使用被篡改或未经授权的令牌。

难以撤销

一般而言,访问令牌通常都有一个过期时间。如果访问令牌被表示为不含任何信息的随机字符串,我们可以在每次向授权服务器验证时检查令牌是否已被撤销。

对于 JWT,由于 JWT 自身包含过期信息,并且 JWT 验证不依赖于授权服务器,一旦授权服务器颁发了 JWT 格式的访问令牌,在其使用期间就无法改变令牌的状态。

当 JWT 令牌自然过期后,我们可以使用刷新令牌从授权服务器获取新的 JWT(有关刷新令牌的信息,你可以参考 Logto的博客)。

然而,在某些情况下,例如用户撤销授权或更改密码时,你需要撤销一个已颁发但尚未过期的令牌时,没有直接解决方案可用。

有两种常见的方法可以减轻令牌中途撤销的影响:

  1. 为访问令牌设置较短的过期时间,并依靠令牌刷新机制来及时刷新令牌的状态。

因为访问令牌有较短的过期时间,当用户发现访问令牌已过期时,他们可以通过授权服务的刷新令牌请求一个新的访问令牌。这样,用户端的令牌状态可以尽快与后端同步。然而,这种方法需要额外的开销,用户需要进行权衡考虑。

  1. 为访问令牌维护一个撤销列表,并在每次验证时检查令牌是否在列表上。

这种方法有一定的限制。JWT 的一个优点是不需要服务器存储状态信息,并且 JWT 通常是无状态的。然而,维护撤销列表需要有效的存储和管理,依赖于额外的存储机制。这实际上牺牲了 JWT 的优势,并可能导致性能问题。因此,令牌撤销机制需要由开发人员以适合其特定使用案例的方式实现。

总结

在本文中,我们简要介绍了 JWT,强调了它的优点和局限性。到现在为止,你应该对 JWT 以及它通常使用的场景有了更深入的理解。虽然 JWT 有其挑战,但在 OAuth 2.0 服务中用作令牌格式所带来的好处远远大于其缺点。

Logto 作为一个快速增长的身份认证服务,也采用 JWT 作为其访问令牌的格式。它严格遵循各种授权和认证协议,使得将身份认证服务集成到你的产品中非常容易。Logto 已正式推出其 SaaS 服务,你可以今天免费试用。