OpenID Connect:验证用户身份的正确方法 - ID 令牌或访问令牌?刷新 ID 令牌?

OpenID Connect: Proper way of authenticating user - ID token or Access token? Refreshing ID tokens?

在我们的 Web 应用程序 (ASP.NET) 中,我们使用授权代码流的 OpenID Connect:

  1. 用户被重定向到身份提供者(例如 Azure AD),进行身份验证,
  2. 授权代码被回发到我们的网络应用程序中的一个页面。
  3. 然后,我们的 Web 应用程序使用授权代码从身份服务器检索刷新令牌、ID 令牌和访问令牌。这些作为 cookie 存储在客户端上(HttpOnly 标志设置为 true)。这是为了避免对服务器状态的依赖,以防负载平衡器将用户路由到不同的 Web 服务器。
  4. 当用户访问页面时,我们会验证 ID 令牌的签名和有效期,并根据应用程序中的用户数据库检查我们用于身份的声明(例如电子邮件地址或 UPN)。

这有效 -- 除了我们无法刷新 ID 令牌,因此用户在 1 小时后超时,需要重新登录。根据 OpenID Connect 规范,当使用令牌端点刷新令牌时,并非所有 OpenID Connect 提供商都会提供新的 ID 令牌。

目前我们看到的备选方案:

  1. 根本不要使用 ID 令牌。使用访问令牌查询用户声明的 UserInfo 端点,并将其缓存在服务器上(在缓存未命中时,例如,如果路由到不同的 Web 服务器 - 只需使用 cookie 中提供的访问令牌再次请求 UserInfo)。由于可以刷新访问令牌,因此这可能会正常工作。
    • 优点:我们得到一个正确刷新的令牌,由服务器验证。
    • 缺点:并非所有声明(例如 aud 和 iss)都由 UserInfo 端点提供,至少对于 Azure AD 是这样。
  2. 不要验证 ID 令牌是否过期,只要它不早于例如12小时。
    • 优点:简单,只需很少的努力即可改变当前的行为。拥有我们今天也拥有的所有权利。
    • 缺点:可能存在安全风险?评论?

那么在较长时间内保持用户登录的推荐方法是什么?将访问令牌与 UserInfo 端点一起使用是否是合适的解决方案?

首先您需要了解每个令牌的用途。 ID Token 供客户端(应用程序)使用。它包含您可以验证以验证最终用户身份(身份验证)的声明。

访问令牌用于授权。它旨在用于受保护的资源(例如:- API 受 OAuth 2.0 令牌保护)。当 API 收到令牌时,它必须对其进行验证并授予访问权限。

刷新令牌用于刷新访问令牌。现在 OpenID Connect 作为 OAuth 2.0 的扩展,允许使用刷新令牌。但是正如您所了解的,ID 令牌可能会或可能不会被刷新。我亲眼看到 Auzre AD 没有刷新 ID 令牌。

您最好的解决方案是在前端和后端之间使用会话。在验证来自令牌请求的令牌后设置此会话。会话存储可以保存最初发送的访问令牌。与此同时,存储刷新令牌。您可以简单地验证 ID 令牌并将其丢弃(假设您将所有必需的信息存储到会话中)。确保此会话是 HttpOnly 和安全的(仅限 Https)。会话过期时间可以等于访问令牌有效期。

访问令牌过期后,您可以使用刷新令牌获取新令牌。无论何时,您的后端都可以将访问令牌附加到来自后端的 API 请求。这样你就永远不会将访问令牌和刷新令牌暴露给前端。

这取决于身份令牌的使用方式。通常它只存在于客户那里。它允许客户端根据强制性 sub 声明对用户进行身份验证。 它不应该用于授权。这就是访问令牌的用途。

在混合流程 (code+id_token) 中,您可以在请求其他令牌之前检查用户的真实性。在那种情况下,一个小令牌是最有效的。

在授权代码流(代码)中,您无论如何都必须使用代码请求令牌。它现在取决于 id_token 中的信息。如果 id_token 不包含配置文件声明,那么您需要从 UserInfo 端点请求信息。

为了访问 UserInfo 端点,您需要访问令牌。缺少的 audiss 声明可能不是问题,因为您由当局本身请求令牌。在我看来,发行者和听众在那时是已知的。

请注意,id_token 不用于授权,因此不存在安全风险。即使 id_token 与资源共享时也不行。

规范要求您按照说明验证收到的令牌。但是当您没有收到新的 id_token 时,为什么要再次验证当前的呢?它可能不是最新的,但已经过验证。

所以我认为这两个选项都很好,但我认为第一个选项更常见。 id_token 很可能在使用后被丢弃。因为访问令牌用于访问资源(包括 UserInfo 端点)和刷新令牌用于刷新访问令牌。

注意一点,用户同意作为过滤条件。如果用户不同意个人资料信息,那么它根本不可用。