【问题标题】:OIDC - Obtaining an Identity Token for use by a backend (no actual user) service running scheduled jobsOIDC - 获取一个身份令牌以供运行计划作业的后端(非实际用户)服务使用
【发布时间】:2021-04-07 15:35:27
【问题描述】:

我们有一个由 OIDC 保护的 API(实际上是几个微服务)。授权服务器由我们的客户(不是我们内部)拥有和管理,并为我们的 SPA 提供身份令牌。然后,该 SPA 将该身份令牌传递给我们的后端服务器,该服务器验证该令牌,提取 SubjectId(用户),然后在内部数据库中查找他们的角色。我们没有使用令牌进行授权(意味着我们忽略声明),它仅用于身份验证。

我们有一个在安全环境中运行的后端 Windows 服务(因此它可以安全地存储机密),它需要调用相同的 API。为了调用 API,它需要一个 OIDC 身份令牌来提供身份验证。安全地执行此操作的最佳方法是什么?

我们已经研究了这些选项:

  1. 用户名/密码流 (OIDC) - 我们拒绝了它,因为它已被弃用。这使得它不是新代码的可靠选择,而且我们不能确定我们的客户现在和将来是否会允许使用它。
  2. 客户端凭据流 (OIDC) - 我们尝试了这个...但它只提供了一个没有身份令牌的访问令牌。我们的全部要求是一个身份令牌(当我们使用它来查找系统中的角色时)......所以这似乎不是一个选项。
  3. 我看了这篇文章:https://nordicapis.com/how-to-handle-batch-processing-with-oauth-2-0/,这很有趣。我可以设置一个不会过期(或非常长)的身份令牌,仅限于一个流或另一个流......但需要我托管和 OIDC 服务器或管理他们的。我们的客户不会提供访问权限。
  4. Martin Fowler 写了一篇关于为此目的使用 Refresh Tokens 的文章:https://martinfowler.com/articles/command-line-google.html 这有两个问题:它是针对 Auth 而不是 OIDC...所以它不处理身份令牌。应该工作,但好奇它是否已经完成。此外,在我的情况下,没有人在刷新令牌过期时刷新它......我需要一些不会过期或可以由后端服务自动刷新的东西。

什么是最好的选择?

【问题讨论】:

  • 只是为了确保我理解...您拥有所有资源(SPA 和 API),但不拥有授权服务器?而且您编写的 API 需要 OIDC 而不是 OAuth?
  • #Andrew 没错。我们的软件部署在客户环境中。他们希望使用其内部 SSO (oidc) 来管理身份验证(但不是授权)。我们接受身份令牌来识别用户的身份,因此我们需要 oidc(提供身份)而不是 oauth(管理访问但不管理身份)

标签: oauth-2.0 identityserver4 openid-connect jwt-auth pingfederate


【解决方案1】:

首先让我说,我不推荐您使用的架构。所以,我会给你两个答案:一个是短期实用的,一个是中期的,这将导致一个更理想的系统。

首先,快速修复:在 API 中开启基本身份验证。然后,使用基本身份验证和长密码从计划任务运行程序调用您的 API,如下所示:

Authorization: basic bXktZ29vZC1zZXJ2aWNlOkY2M0JEOTkyLTMzNTUtNDYzNi1CNzFBLTM3RDg0QzI3ODEzRQo=

然后,继续验证您从 SPA 获得的 ID 令牌。我假设您使用 RFC 6750 中描述的技术将其发送到 API:

Authorization: bearer eyJhbGciOiJSUzI1NiJ9.ey...

因此,这两种不同的身份验证方法使 API 可以轻松判断谁在调用它。更重要的是:它应该是容易实施的,即使授权发生了变化。希望这可以让您扑灭大火,然后在更根本的层面上解决问题。

当你达到这一点时,我建议你做两件事:

  1. 添加您自己的令牌服务(即授权服务器)。 API 应该只信任它自己的授权服务器,而不是某个外部的。这将形成一个枢轴点,这是您现在需要而没有的。

  2. 仅在您的 API 中接受访问令牌。 API 应该只使用访问令牌。如果 API 接受 ID 令牌,则有 99% 的可能性是它做错了。

SPA 是您图片中唯一需要 ID 令牌的地方。它应该得到那个一个访问令牌。更重要的是,它应该从您的 OpenID Connect 提供商 (OP),而不是您的客户那里获得此信息。这应该反过来向您的客户执行 OpenID Connect,但通常会处理身份验证,以便您的应用程序可以在未来应对其他身份验证要求,而无需更改 SPA。此外,其他应用程序可以重用所有这些。

SPA(和调度服务)应将访问令牌发送到 API。令牌(或它的phantom or split form)至少应包含主题 ID,以便它可以获得授权调用所需的更多信息。这应该来自您的令牌服务(即您的新 OP,因为它将执行 OAuth 和 OIDC)。

我会推荐以下高级架构文档和视频。这些将有助于您继续改进实施:

【讨论】:

  • 感谢您的详尽回复。我也喜欢最后的链接,并发现它们提供了丰富的信息。据我了解,您在当前设计中看到的两个问题是:1)我应该使用访问令牌,而不是身份令牌来调用我的 API 和 2)OAuth 服务器不是我系统的一部分,它是一个外部服务器。我应该添加另一个 OAuth 服务器来创建访问令牌以提供对 API 的访问
  • 这会导致 2 个问题(如果您不介意的话):我们的授权逻辑不能使用是或否术语来描述......它与用户及其内部声明有关(不知道OAuth 服务器)。意思是,一个人在公司的职位,或者他们从事的产品将限制他们能看到的东西。如何将该身份传递给 API?访问令牌很好,但对我来说没有足够的信息
  • 第二个问题:整个系统在本地为每个站点的单个客户托管。 OAuth 服务器属于该客户并控制对许多应用程序的访问。一旦它将身份信息传递给我的 API 进行登录,将其转换为另一个令牌有什么好处?为什么不直接使用来自其内部 OAuth 服务器的访问令牌或身份令牌?是否允许我的 API 控制访问令牌并对其进行专门化?
  • 是的,您已经正确理解了我对您的设计的“问题”。 Q1:很多人的API和你一样有复杂的授权逻辑。大多数人没有意识到 OAuth 访问令牌不仅可以具有访问范围,还可以具有声明。如果需要,您也可以从您的 API 中查找其他声明。因此,使用访问令牌在 API 中执行复杂的授权逻辑应该是非常可行的。如果不清楚,请查看:curity.io/resources/architect/claims/scopes-vs-claims Q2:避免意大利面条式信任youtu.be/pua07chpYBU?t=872
  • #Travis 感谢您的意见。
【解决方案2】:

不太确定您的用例,但在我看来,我可能会这样做:

SPA 根本不处理令牌,而是只给它一个会话 cookie。让一切更加安全。

让服务调用 OIDC 服务器以获取其自己的访问令牌,该令牌可以包含调用 API 所需的必要子或角色声明。

【讨论】:

  • 感谢您的回复。我的问题是我没有使用 OAuth/OIDC 来管理角色声明。这是客户的要求,所以没有商量余地。相反,OIDC 仅将身份验证作为身份令牌提供,并且角色在 API 本身中进行管理。我无法使用客户端凭据流,因为它不返回身份令牌,并且它返回的访问令牌无法调用 UserInfo 端点
  • 要获得 ID-token,您需要手动(作为用户登录并给予同意)。所以我图片中的唯一选择是让后台服务向客户端服务询问要使用的 ID 令牌。
  • 很有趣...但是这将如何工作。如果后端服务调用“客户端服务”来获取身份令牌,客户端服务将如何对后端服务进行身份验证,以便知道要为哪个用户获取令牌?此外,如果没有实时用户提供身份验证和同意,客户端服务如何获取该令牌?
  • 用户需要手动登录一次,然后获取ID和访问令牌。 ID-token 的默认生命周期只有 5 分钟,因此它主要用于创建与 SPA 的本地会话。访问令牌可以永远与我们一起使用,而无需使用刷新令牌来更新它们。由于客户端是私人客户端(可以保密),因此没有什么可以阻止您创建本地内部 API,服务可以使用该 API 来获取令牌的副本。或者客户端将令牌写入本地磁盘....
  • 然后根据 OIDC 服务,还有一个选项是客户端可以通过使用令牌交换向 IdentityServer 请求新的访问令牌,特定于服务可以使用的 API,请参阅 @ 987654322@这也许是一个更干净的解决方案。
猜你喜欢
  • 1970-01-01
  • 2019-12-21
  • 2021-10-29
  • 2016-12-08
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
  • 1970-01-01
  • 2019-01-19
相关资源
最近更新 更多