【问题标题】:Implementing OAuth 2 in a multi-tenant application using dynamic scopes使用动态范围在多租户应用程序中实施 OAuth 2
【发布时间】:2019-01-10 11:33:14
【问题描述】:

我目前正在尝试将多租户系统从“自定义”身份验证和授权实施迁移到 OAuth2。

多租户模型与 GitHub 的结构非常相似,因此我将使用它作为主要示例。假设在应用程序中我们有用户、存储库和组织。用户可以直接访问存储库,也可以通过他们所属的组织访问存储库。根据他们的访问权限,用户应该对管理它们的用户拥有对存储库和子资源(如 /repository/issues)或组织及其子资源(/organization/members)的不同权限。与 GitHub 的 OAuth2 解决方案不同,该系统应该能够跨存储库或组织提供不同级别的权限(GitHub 通过自定义实现在不同级别上提供)。

目标是保持逻辑尽可能简单,将所有内容封装在授权服务中,并尽可能多地搭载 OAuth2。

我的方法是部署通用 OAuth2 服务,并使用动态范围处理权限:

  • user:read
  • user:write
  • repo:read
  • org:read
  • repo:<repo_id>:issues:read
  • repo:<repo_id>:issues:write
  • org:<org_id>:members:read
  • org:<org_id>:members:write

这为客户端和用户启用了细粒度的权限,例如用户可以在他的一个存储库中read + write 问题,但在另一个存储库中只能read

虽然这似乎解决了问题,但主要限制是能够请求范围。由于用户不知道他们有权访问的存储库和组织的 ID,因此他们在联系授权服务器时无法请求正确的范围列表。

为了克服这个问题,我考虑了 2 个解决方案:

解决方案 1

  1. repo:readorg:read 颁发令牌
  2. 检索用户有权访问的存储库和组织列表
  3. 使用所有必需的范围发出第二个令牌

深思熟虑后,事实证明这是不可行的,因为它不支持像 implicitauthorization_code 的授权,除非授权服务器会处理这种资源“发现”。

解决方案 2

前 2 个步骤与第一个解决方案相同,而对于第 3 个步骤,用户将只能发布租户范围内的令牌。通过extending the OAuth2 with a parameter 识别租户(/authorize?...&repo=<repo_id>),使用授权码授权的客户端必须为每个租户颁发令牌。在步骤 1 中发布的令牌必须在授权服务器上保留用户的身份,并且当用户在租户之间切换时无需重新验证。这种方法的缺点是它增加了客户端集成的复杂性,并且可能会以某种方式违反标准。

我正在寻找对此的第二意见,这可能会简化问题并确保解决方案符合标准。

【问题讨论】:

    标签: authentication oauth oauth-2.0 authorization standards


    【解决方案1】:

    tldr;使用自包含访问令牌传达用户身份信息并持有 API 端点定义的访问策略怎么样?

    您现在面临的问题是由于 OAuth 2.0 scope 的功能不匹配。 Scope value in OAuth 2.0 被定义为供客户端应用程序使用。

    授权和令牌端点允许客户端指定 使用“范围”请求参数访问请求的范围。

    但在您的方法中,您尝试使其由最终用户(人类用户)定义。

    一种解决方案是使授权服务器独立于权限细节。这意味着,授权服务器仅发布对您的服务/系统有效的令牌。这些令牌可以是独立的,包含用户标识符和可选的组织详细信息(声明)。它可能包含您的服务所需的其他详细信息(由您决定)。理想的格式是使其成为 JWT。

    一旦您的客户端(系统的消费者,如 GIT 网站)获得此令牌,它就可以调用系统后端。一旦您的系统支持收到令牌,它就可以验证令牌的完整性、所需的声明并使用这些声明来确定为该特定用户授予了哪些资源。您为范围定义的权限级别现在存储在您的服务后端中。

    这样做的好处是能够让用户身份驻留在任何地方。例如,您可以使用 Google 或 Auzure AD,只要他们可以为您提供有效的令牌,您就可以支持此类用户使用您的系统。这是理想的,因为权限没有存储在其中。超级用户将有能力定义和维护这些权限。

    【讨论】:

      【解决方案2】:

      同意@Kavindu Dodanduwa 提到的所有内容,但想在这里添加一些额外的细节。

      这个问题确实超出了标准 OAuth 2.0 的范围。如果你想管理每个资源的权限(例如每个 repo 或组织),这应该在你的服务或它前面的网关中处理。通常,您需要在后端存储某种access-control list (ACL),然后您可以使用它来授权用户。

      如果您想查看现有标准,请查看 XACMLUMA(它是 OAuth 2.0 的扩展)。但是我发现它们的实现和管理相当复杂,尤其是在分布式环境中。

      相反,我建议使用 sidecar 对您的服务执行授权的替代解决方案。查看相关博文:

      Open Policy Agent 可能是此类架构的一个很好的解决方案。

      【讨论】:

      • 谢谢!我最终在研究时获得了相同的资源,并得出结论,将行级授权封装到资源服务中将提供更好的解耦,尽管这需要更大的实施工作。
      猜你喜欢
      • 1970-01-01
      • 2023-03-28
      • 2011-11-24
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      相关资源
      最近更新 更多