了解 OpenID Connect (OIDC) 协议中的 refresh token, access token 和 ID token

查看 48|回复 1
作者:logto   
简介
OpenID Connect 协议,也称为 OIDC ,已成为广泛采用的标准,为身份管理提供了基本框架。
它是一个建立在 OAuth 2.0 协议之上的身份验证层。OAuth 2.0 仅用于资源授权,而 OIDC 通过新引入的 ID token 来标准化和加强身份认证。
我们的产品 Logto 是一个的客户身份和访问管理( CIAM )解决方案,正是构建在 OIDC 协议之上。在我们的社区中,用户经常问到一个问题:

Refresh token, access token 和 ID token 之间有什么区别?

在本文中,我们将探讨这些 token 的含义,同时阐明 Logto 如何增强整体开发者体验。
从一个实际场景开始
假设你正在处理一个典型的客户端 - 服务器应用,它们通过 RESTful API 进行通信;你还有一个可用的 OIDC 服务。对于私有 API ,你希望只有经过授权的客户端才能访问。马上就会有一个问题出现:
为保护我的 API ,我需要哪种类型的 token ?
快速答案是:access token 。
在 Resource Indicators for OAuth 2.0 (RFC 8707) 中,每个受保护的 API 都被视为一个「资源」。Access token 是客户端在请求 API 资源时传输到服务器的凭据(可以想象成一把钥匙),通常通过请求 header 进行传递。在服务器端,每当收到请求时,服务器只需验证传入请求是否携带有效的 access token 。

ℹ️ Access token 是一种短期凭据,用于授权用户访问受保护的资源。当用户使用 OIDC 成功进行认证时,授权服务器会颁发 access token 。在 Logto 中,access token 会以 JSON Web token (JWT) 的形式返回。
该 token 包含有关用户、其权限以及其有效期的信息。你可以将其附于每个后续请求一起发送到资源服务器,以便资源服务器验证用户是否有权访问该资源。

对于包含签名的 access token ,资源服务器甚至可以在不请求授权服务器的情况下验证其有效性(离线验证)。这极大地提高了性能,因为资源服务器不必在每次请求时都与授权服务器进行通信;其安全性也得到了保证,因为签名的 access token 无法被篡改。

🤔️ JWT 签名与验证涉及到一些复杂的数学运算和密码学概念,这超出了本文的范围。我们之后可能会撰写一篇文章来详细介绍这个话题。

然而,你可会想:如果我的客户端应用程序在成功登录后可以获得有效的 access token ,并使用该 access token 请求服务器 API ,那不就足够了吗?为什么我还需要 refresh token 和 ID token ?
这是一个很好的问题,让我们一个个来。
为什么我们需要 refresh token ?
尽管技术上 access token 满足使系统正常工作的最低要求,但出于安全考虑,access token 的有效期通常很短(通常为一小时)。因此,想象一下,如果我们只有 access token ,最终用户将不得不在每次 access token 过期时重新进行身份验证。对于现代单页 Web 应用程序,特别是移动应用程序来说,经常性地登出是一种相当痛苦的用户体验,尽管我们只是在努力保护他们的用户安全性。
因此,我们需要在 token 安全性和用户便利性之间取得平衡。这就是 OAuth 2.0 引入 refresh token 的原因。

ℹ️ Refresh token 是一种较长寿命的 token 。当 access token 过期或需要更新时,可以使用 refresh token 在无需用户重新认证的情况下获取新的 access token 。与 access token 相比,refresh token 的有效期较长,通常持续几天、几周甚至几个月。

为什么 refresh token 可以具有较长的生命周期?
Access token 用于访问 API 资源,因此其较短的有效期有助于减少泄漏或受损的风险。Refresh token 有以下特点:
  • Refresh token 仅用于交换新的 access token ,它们不像 access token 那样频繁使用,因此暴露的风险降低。
  • Refresh token 无法直接访问资源,当发现它们被泄露时,授权服务器可以立即撤销它们。

    因此,refresh token 的较长有效期被认为是可以接受的。
    确保 refresh token 的安全性
    由于 refresh token 也存储在客户端,确保它们不被破坏是有挑战的,尤其是对于公共客户端,如单页 Web 应用程序( SPA )。
    在 Logto 中,refresh token 默认启用了自动的 轮换机制,这意味着授权服务器将在满足以下条件时发行新的 refresh token:
  • 单页应用程序:一种公开且不可信的客户端,这些应用会在每次客户端请求 token 时进行 refresh token 轮换。
  • Native 和传统 Web 应用程序:当达到其 TTL 的 70% 时会自动更新(了解更多)。

    虽然你仍然可以在 Logto Console 的应用程序详细信息页面上禁用 refresh token 轮换,但我们强烈建议保留这项安全措施。
    ID token
    ID token 使客户端能够在不请求服务器的情况下获得基本用户信息。

    ℹ️ ID token 是 OIDC 引入的新 token 类型,它包含缓存的用户认证信息,提高了性能和终端用户体验。与只能被资源服务器理解的 access token 不同,ID token 对客户端友好。当客户端发起 OIDC token 交换请求时,可以请求一个 ID token 和一个 access token 。

    ID token 的表现形式为 JSON Web token ( JWT ),其中包含用户声明( claims ),如用户名、电子邮件、头像图片等。它由授权服务器签名,可以由客户端离线验证和解码。
    这对于 SPA 和 native 应用程序特别有用,客户端可以缓存 ID token 并使用它来确定用户的身份验证状态,而不用依赖于服务器。
    还需要注意的是,ID token 不用于授权访问受保护的资源(可以想象成身份证); access token 才是这个角色的合适人选。

    🔑 在实践中,我们看到有些开发者在 access token 中包含大量用户声明,这是不推荐的。如果能直接用钥匙开门,为什么要把身份证也带在身上呢?

    我们的 SDK 中使用 ID token 来帮助确定客户端上的身份验证状态。例如,在我们的 JS SDK 中:
    const isAuthenticated = Boolean(await this.getIdToken());
    然而,正如上面提到的,客户端 SDK 的 isAuthenticated 标志仅是一个客户端缓存的状态。实时的身份验证状态仍然需要通过 refresh token 和 access token 来确定。
    我们还在 SDK 中提供了一个 getUserClaims() 函数,以帮助解码 ID token 并获取用户声明。如果您想从 OIDC 服务器获取全面和实时的用户信息,可以使用 fetchUserInfo()。
    Logto 的优势和功能
    Logto 和附带的 SDK 严格遵循 OIDC 协议,同时为开发者和企业提供了额外的功能和优势:
    [ol]
  • 便捷的 SDK:Logto SDK 可大幅简化 token 管理。你不必手动存储 refresh token 和 access token 。只需每次调用 getAccessToken(),SDK 将始终尝试重用已存储的 access token ,或在其过期时自动通过 refresh token 更新它。
  • Refresh token 轮换:Logto 默认开启 refresh token 轮换机制,确保在 refresh token 被使用后始终对其进行更新,从而减轻泄漏或受损的风险。你仍然可以在管理员控制台中禁用它,但我们强烈建议保持启用。
  • 性能优良:借助 ID token ,你可以在不请求服务器的情况下获取基本用户信息。利用 Logto SDK 提供的 isAuthenticated 状态和 getIdTokenClaims() 函数,就可以在客户端上检查用户的身份验证状态并解码用户声明。
  • 增强的安全性:Logto 使用 HTTPS 和 TLS 在客户端与授权服务器之间强制实施安全连接。这可以保护 token 免受未经授权的第三方潜在盗窃,并确保你的系统安全。
    [/ol]
    小结
    在 OIDC 协议中,refresh token ,access token 和 ID token 共同提供了安全且无缝的用户身份验证体验。
  • Refresh token 消除了用户为获取新 access token 而频繁登录的问题。
  • Access token 可以访问受保护的资源。
  • ID token 在客户端上提供缓存的用户信息,提升了性能。

    了解这些 token 的角色和用法对于采用 OIDC 进行身份验证的开发者来说至关重要,希望大家评论中分享你的想法和经验;同时,也欢迎大家试用我们的产品:
    网站 https://logto.io GitHub https://github.com/logto-io

    token, Access, Refresh, logto

  • lanlanye   
    > 由于 refresh token 也存储在客户端,确保它们不被破坏是有挑战的,尤其是对于公共客户端,如单页 Web 应用程序( SPA )。
    在 OAuth 2.0 中,刷新令牌( refresh_token )是用于获取新的访问令牌( access_token )的凭证。根据 OAuth 2.0 规范,refresh_token 是下发给授权服务器的授权客户端的,而不是直接给终端用户。
    另外我不明白把基本的用户信息也放进 access_token 有什么不好?
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部