【问题标题】:OAuth2 flow from resource server to anotherOAuth2 从资源服务器流向另一个
【发布时间】:2017-12-22 03:03:02
【问题描述】:

与实施无关的讨论。

假设下图。

  • 黑线显示哪些服务受身份验证服务器保护。
  • 绿线表示服务之间的交互(Customer 和 Orders 服务需要通过 Data 服务才能访问数据库。StandAlone 服务不像其他服务)
  • 红线表示特定的请求流程
  • 数据服务不直接暴露在外部,只能由允许这样做的其他服务访问。

我假设当用户通过身份验证服务器进行身份验证时,客户端已获得访问令牌。选择了哪个流(隐式、授权码、密码)无关紧要。我想从客户端已经获得访问令牌开始讨论。

从那时起,我很清楚当客户端需要访问单个资源服务器时会发生什么。

  1. 向资源服务器发出请求并传递获取的令牌
  2. 资源服务器验证令牌(与方式无关)
  3. 如果有效,则提供请求。

因此,在该图中,如果客户端要访问“独立服务”(不与任何其他资源服务器对话),那么流程对我来说很清楚。

当客户遵循图中的红线时,我遇到了麻烦。所以我需要访问一个服务(资源服务器),为了回复需要访问另一个服务(也是资源服务器)。在这种情况下流程如何?

场景 1.

  1. “订单服务”设置为资源服务器和客户端。
  2. 客户端使用访问令牌发出请求,但“订单服务”将使用自己的客户端凭据获取另一个令牌,以便与“数据服务”通信。

我看到的问题是我失去了用户权限。我将使用“订单服务”权限而不是用户权限执行对“数据服务”的请求。

场景 2。

  1. “订单服务”仅设置为资源服务器。
  2. 客户端使用用户令牌发出请求,“订单服务”会将相同的令牌转发到“数据服务”

在这里,我使用用户的权限执行,但现在我看到我的“数据服务”已公开并对任何其他服务开放。 (其实我不知道 oauth2 是否提供了这样的限制。将客户端仅限于特定的资源服务器)

场景 3。

在这里,我看到了上述场景的组合,其中“订单服务”将为数据服务提供两个令牌。用户访问令牌,以便使用正确的权限和“订单服务”客户端访问令牌执行请求,以便我知道允许该服务与“数据服务”对话。

实施

我正在使用 spring boot 和 spring security 来设置上面看到的我的 oauth2 组件。我已经有一个身份验证服务器、一个资源服务器和一个客户端。客户端此时与资源服务器对话,而请求未委托给另一个资源服务器。

根据最佳方法,我将如何在实施方面进行?我需要对我的资源服务器进行哪些更改,以便它们可以安全地相互通信?

感谢您的宝贵时间

【问题讨论】:

    标签: security spring-security oauth-2.0 spring-oauth2


    【解决方案1】:

    根据我的理解,第一种方法似乎是正确的,因为“订单服务”充当“数据服务”资源服务器的客户端。所以它应该使用作为客户端提供给它的访问令牌。

    OIDC 专门用于客户端(阅读 here 。还可以在该页面上查看“为什么使用访问令牌到安全 API”),任何资源服务器都不应该将该 id_token 用于任何事情(但它是确实,每个实施者都在这件事上遵循自己的决定,所以这很令人困惑。我建议阅读here)。

    因此,在我看来,我们有以下替代方案来满足您的要求:

    1. “订单服务”充当客户端,完全控制“数据服务”资源(或至少是您想要访问的“资源类型”)。如果您需要向“数据服务”提供一些有关谁是“订单服务”的发起者的信息来请求任何内容,那么这是请求资源时有效负载的一部分(它不是 access_token 的一部分)。
    2. 资源所有者(用户)之前已授予对其“数据服务”特定资源的“订单服务”的特定访问权限。与前一点类似,但“订单服务”无法访问所有“数据服务”资源。来自发起者的信息仍然是有效载荷的一部分。
    3. 为了避免将发起者信息作为有效负载的一部分传递,我想我们需要能够“按需”生成“订单服务”客户端凭据,其中包含一些关于它们链接到的资源所有者的字段,或者以某种方式之前创建的用户他们并链接到他的个人资料,以便以后可以通过“订单服务”检索。这就是我的理解开始变得混乱的地方,并且文档不清楚(OAuth2 RFC 没有涵盖这一点)。
    4. 将整个系统视为一个整体,只有一个客户端。从前端客户端(用户与之交互的客户端)收到的 access_token 包含所需的所有特定范围。 “客户端”、“订单服务”、“客户服务”都共享相同的客户端凭据,并且只是将“访问令牌”从一个转发到另一个(因此它不再是“客户端凭据授予”)。所以他们都有完全相同的权限集。资源所有者将在首次登录授权服务器时授予这些权限,因此还不错。但很明显,这意味着您无法优化来自每个“子模块客户端”的权限,并且资源服务器将无法根据访问令牌 userinfo 请求确定来自哪个“子模块”的请求(如果需要,它应该是有效负载的一部分)。这肯定有安全隐患。

    到目前为止,我只使用了替代 4(用于内部网络)。所以不能多说现实世界中的其他 3 个。

    我还没有看到基于“社区接受的标准”的具体解释,说明如何达到您的要求(这并不直接与规范相矛盾)。

    【讨论】:

      【解决方案2】:

      我有同样的情况(我们称之为服务器到服务器的调用情况),到目前为止,我已经通过将服务 A 设置为服务 B 的 oauth2 客户端来访问它,以进行服务 A -> 服务 B 调用。

      当您将服务 A 设置为服务 B 的 oauth2 客户端时,它与用户原始令牌的 oauth2 范围无关。因为它是服务 A 调用服务 B,所以 A 应该能够使用 A 自己的 oauth2 访问令牌调用 B,该令牌具有 A 调用服务 B 所需的所有 oauth2 范围。

      为了做到这一点,您可以 1) 在 A 端使用某种配置并在调用服务 B 时在 SecurityContextHolder 中交换 OAuth2Authentication,并在从服务 B 获得响应时恢复原始 OAuth2Authentication 或 2) 添加逻辑在服务 A 中请求具有预先配置的 oauth2 clientId 和秘密的访问令牌并使用它来调用服务 B。(需要完成与案例 #1 中提到的相同的交换逻辑。

      如果您不将服务 A 视为服务 B 的 oauth2 客户端,而是使用与原始用户令牌相同的 oauth2 范围,那么您最终将无法继续授予下游服务调用所需的任何 oauth2 范围用户的 oauth2 访问令牌,并且当进行多个服务到服务调用时(或者当下游调用的 oauth2 范围被添加/修改时),您将永远无法正确跟踪它。通过将服务 A 视为服务 B 的 oauth2 客户端,您只需要注意服务 A 的 oauth2 clientId(或 access_token)的授权范围。

      【讨论】:

        【解决方案3】:

        您正在混合授权和身份概念。

        oauth2 角色(resource ownerresource serverauthorization serverclient)是角色而不是身份。您的订单服务在一种情况下具有resource server 角色,在另一种情况下具有client 角色。

        场景 1 是正确的方法。

        Oauth2 令牌确实与某些资源标识符相关联,因此将客户端限制为特定资源是一项内置功能。

        客户端相关的授权集使用 Oauth2 scope 概念处理

        如果您想在请求流中传播最终用户身份,您必须在整个流中传播身份令牌(例如 JWT 令牌)(请参阅OIDC)。但是,处理最终用户授权可能不是数据服务的责任。

        【讨论】:

          猜你喜欢
          • 2020-02-23
          • 2018-10-18
          • 2013-12-21
          • 2018-04-14
          • 2017-12-15
          • 2019-02-16
          • 2018-05-01
          • 2013-08-24
          • 2019-10-27
          相关资源
          最近更新 更多