使用 OAuth 访问 SPA 和 REST 时,RBAC 的用户组成员身份应该存储在哪里 API

Where should be user group membership stored for RBAC when using OAuth to access SPA and REST API

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

用例是

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

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

我的另一个问题是,如果我想允许自动客户端访问无法使用授权流程的 REST API,最好的做法是使用客户端流程和在 keycloak 中的那个客户端上并提供客户端 clientId 和秘密以便能够检索访问令牌使用它来对 REST 服务进行身份验证(Bearer 身份验证 header)

更新

我还有几个跟进问题希望能弄清楚。

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

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

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

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

获取该信息 (groups/permissions)

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

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

(不幸的是)现实世界中已经有不遵循此约定的应用程序(嗨,Concourse :-))。他们期望在 ID 令牌中使用 groups/roles,而您无法配置它。这是 Keycloak 支持访问令牌和 ID 令牌中声明的一个很好的原因。

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

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

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

Another question that I have is that if I want to allow an automated client to access the REST API which won't be able to use authorization flow is it in the best practice to use client flow and on board that client in keycloak and provide the client clientId and secret to be able to retrieve access token use it to authenticate to the REST service (Bearer authentication header)

正如 Jan 指出的那样,客户端凭证流正是为此目的而创建的——这样后端就可以相互通信。这是一种对客户端进行身份验证的方法。

What is still not clear is that if an application received an authorization token doesn't that mean the user is authenticated. Why do we need ID Token.

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

Also, if access token does not always carry information and could be just a random string then how would you know user's permissions. I was reading that there are two types of tokens “identifier type” and “self-contained type”. I am guessing that if the token is an identifier type then REST Service will have to send a request to the authorization server to get that information (groups/permissions) via retrospect api.

确切地说,如果您使用不透明字符串作为访问令牌,那么 API 将必须执行自省流程(RFC 7662) to the Authorization Server to validate the token and get the associated authorization information (like user's groups, etc.). If you're concerned that this is a lot of traffic between your services and the Authorization Server you can have a look at a pattern called the Phantom Token flow 中定义的标准,它利用 API 网关和它的缓存来执行自省而不是服务本身。我建议使用这种方法,特别是当你说你将有 3d 方客户端访问你的 API 时。最好不要与 3d 方共享 JWT 访问令牌集成商。

另请参阅这篇关于 API Security Best Practices 的文章,它可能会让您更加了解这些内容。