使用 OAuth 访问 SPA 和 REST API 时,应该在哪里为 RBAC 存储用户组成员资格

问题描述

我正在努力实施 oauth2 以保护将调用 REST API 的 Web 应用程序,并允许其他潜在客户端访问相同的 REST API。我想使用基于角色的访问来控制从 API 返回的数据。
我将使用 Keycloak 作为授权服务器以及用户/组管理。

用例是

  1. 我将使用公共客户端 (SPA) 和机密的可能仅承载客户端 (REST API) 以及将成为这些组的一部分的组和用户创建 keycloak 领域
  2. 用户将通过授权流程登录 SPA 并收到访问令牌。
  3. SPA 将向 REST 服务发出请求 (XHR),将令牌作为不记名令牌传递,并根据用户所在的组检索数据或执行允许的操作。

我正在尝试了解/最佳实践,我应该在哪里存储用户所属的组列表。是在访问令牌中还是在可由 SPA 和/或 REST 服务检索和传递的 ID 令牌中,必须使用访问令牌和 userinfo 端点从授权服务器检索该数据。似乎 keycloak 使用 JWT 进行访问和 ID 令牌,角色/组可以包含在两者中。我读到了混合建议,即 REST 服务不应读取访问令牌,仅用于证明用户已通过身份验证,但后来我看到它用于传递用户组。

我的另一个问题是,如果我想允许自动客户端访问无法使用授权流程的 REST API,最佳实践是使用客户端流程并在 keycloak 中加载该客户端并提供客户端 clientId 和密钥以便能够检索访问令牌,使用它来对 REST 服务进行身份验证(承载身份验证标头)

更新

我还有几个后续问题,希望能说明一切。

就 ID 令牌而言,我认为 ID 令牌仅应由对用户进行身份验证的应用程序 (SPA) 使用,并将获取有关用户的信息(用户名、电子邮件和其他一些内容)关于声明和用户批准权限。可能会在应用程序中显示这些东西。不应(永远)将 ID 令牌发送到 REST API 以检索数据。

另一方面,访问令牌不应被应用程序 (SPA) 读取,而应在对 API 服务器 (Bearer $AUTH_TOKEN) 的每个请求中使用,API 服务器验证令牌,然后检索用户的组信息并返回允许回复

尚不清楚的是,如果应用程序收到授权令牌并不意味着用户已通过身份验证。为什么我们需要 ID Token。

此外,如果访问令牌并不总是携带信息并且可能只是一个随机字符串,那么您如何知道用户的权限。我读到有两种类型的令牌“标识符类型”和“自包含类型”。我猜如果令牌是标识符类型,那么 REST 服务将必须向授权服务器发送请求以通过回顾 API 获取该信息(组/权限)。

找到两篇关于这个的好文章
https://darutk.medium.com/oauth-access-token-implementation-30c2e8b90ff0
https://darutk.medium.com/api-protection-by-id-token-3123481e96f2

解决方法

Keycloak 提供开放式 ID 连接 (OIDC) 标准。 OIDC 基于 OAuth 2.0。仅当您使用 OIDC(身份验证请求中的 openid 范围)时,您才会获得 ID 令牌。 ID 令牌应用于身份验证。我会说身份验证不需要了解有关用户组的任何信息。组/角色仅对授权很重要,这是 OAuth 的一项任务 - 访问令牌。所以我会在访问令牌中保留组/角色。

(不幸的是)现实世界已经有应用程序,它们不遵循此约定(您好 Concourse :-))。他们需要 ID 令牌中的组/角色,而您无法对其进行配置。这是 Keycloak 支持访问令牌和 ID 令牌中声明的一个很好的理由。

推荐博文:https://medium.com/@nilasini/id-token-vs-access-token-17e7dd622084

OAuth 为机器到机器应用程序提供客户端凭据流,因此它是自动化客户端的正确选择,例如 cron/CI 脚本、第 3 方应用程序访问等,在这些地方您不需要用户身份。

,

您应该始终将授权信息放在访问令牌中,而不是 ID 令牌中。例如,如果您在客户端中需要用户组的信息,则有关用户组的信息可以出现在 ID 令牌中 - 也许您想根据用户组等对某些信息进行颜色编码。

我的另一个问题是,如果我想允许自动客户端访问无法使用授权流程的 REST API,最佳实践是使用客户端流程并在 keycloak 中加载该客户端并提供客户端 clientId 和密钥以便能够检索访问令牌,使用它来对 REST 服务进行身份验证(承载身份验证标头)

正如 Jan 所指出的,客户端凭据流正是为此目的而创建的 - 以便后端可以相互通信。它是一种对客户端进行身份验证的方法。

尚不清楚的是,如果应用程序收到授权令牌并不意味着用户已通过身份验证。为什么我们需要 ID Token。

正如您所写的那样 - 访问令牌用于 API,ID 令牌用于客户端。当然,当您的客户端获得访问令牌时,这意味着该用户已通过身份验证,但许多客户端希望获得有关已验证用户的其他信息,因此他们可以例如显示您的个人资料图片、您的用户名、知道您的电子邮件等。因此 ID 令牌 - ID 令牌为您提供有关已验证用户的信息,不仅证明他们已通过身份验证。如果您只需要证明用户已通过身份验证,那么访问令牌就足够了。

此外,如果访问令牌并不总是携带信息并且可能只是一个随机字符串,那么您如何知道用户的权限。我读到有两种类型的令牌“标识符类型”和“自包含类型”。我猜如果令牌是标识符类型,那么 REST 服务将必须向授权服务器发送请求以通过回顾 API 获取该信息(组/权限)。

确切地说,如果您使用不透明字符串作为访问令牌,则 API 将必须执行到授权服务器的自省流程(RFC 7662 中定义的标准)以验证令牌并获取相关的授权信息(如用户组等)。如果您担心服务和授权服务器之间存在大量流量,您可以查看一种称为 Phantom Token flow 的模式,该模式利用 API 网关及其缓存来执行自省,而不是服务本身.我建议使用这种方法,尤其是当您说您将有 3d 方客户端访问您的 API 时。最好不要与 3d 方集成商共享 JWT 访问令牌。

也可以看看这篇关于 API Security Best Practices 的文章,它可能会让你对这个东西有更多的了解。