OpenID Connect/Oauth2 - cache/use tokens
我有一个带有REST API的系统。 REST API的用户应该能够使用通过Oauth2的OpenID Connect进行身份验证。该系统本身具有其自己的许可系统。我需要将IDP用户映射到我的本地权限系统。我正在考虑将openid范围子键保存在本地数据库中,作为唯一的用户标识符。
但是我应该在API中将哪个令牌返回给用户。它应该是来自OpenID Connect层的oauth2访问ID还是token_id,或者两者都是?
因此,我为API的最终用户看到了这些替代方案:
1
| Authorization: Bearer <token_id> |
1 2
| Authorization: Bearer
TokenID: <token_id> |
在不将token_id / access_id保留在系统中的情况下,我需要针对每个API请求从客户端获取此令牌。令牌ID包含JWT声明(子),因此我需要使用它来验证客户端可以在我的系统中执行的操作。
我是否需要在本地数据库中存储以下任何ID以验证API请求,或者用户应提供它?
我基本上是在进行身份验证和用户标识之后。我没有访问过除此以外的任何外部资源。
最后一个问题。我是否需要验证对IDP的每个请求的访问令牌,还是可以对其进行缓存?使用OpenID Connect时是否需要同时验证访问令牌和令牌ID?
编辑:
我的系统本身具有REST API和其自己的权限系统。权限系统使用由使用OpenID Connect的任何身份验证系统提供的用户ID。将第一个用户手动添加到权限系统。
思想流:
我系统的用户请求https:// mysystem / login
用户被重定向到https:// idp / auth
IDP将成功登录重定向到https:// mysystem / callback
我的系统从令牌ID JWT获取用户ID(子)和电子邮件。
然后使用访问令牌(不是OIDC令牌ID)返回给用户。
用户现在可以执行:curl -H"授权:承载
访问令牌" https:// mysytem / some / resource
Mysytem从用户那里收到此请求,但不知道如何将访问令牌映射到数据库中的用户ID,而没有向IDP询问用户ID。
我想使用外部IDP来让用户登录,而不是从第三方系统访问资源。
更新
访问令牌没有用户ID-请参见本文的第14步。为什么您认为不是呢?
该规则的一个例外是没有用户参与时-应用到应用之间的通信(例如,客户端凭据流)。但是您没有使用它。
原始答案
您应该只将UI中的完全访问权(承载)令牌发送到API,并且无需在数据库中存储令牌详细信息。
迁移到OAuth架构时,您会将用户数据存储在2个地方:
-
您的常规产品数据库-通常包含角色和用户权限
-
授权服务器-生成唯一的用户ID
根据您的建议,在产品数据中存储唯一的用户ID以进行关联和跟踪是很常见的。登录后,您的API通常需要根据产品数据进行授权。
我的一些博客文章更详细地介绍了这些主题:
我的博客还链接到将这些概念联系在一起的示例代码。
- 因此,我将我的权限系统与IDP中的用户ID结合在一起。但是,如何将访问令牌(在API请求的载体中提供)映射到数据库中的用户?还是我需要为每个请求查找/ userinfo以获得子ID以映射到我的数据库?我只是不知道如何在我的数据库中向用户映射访问令牌。
-
如果您已有用户,则通常在首次为用户完成登录时通过电子邮件在OAuth数据和产品数据之间进行匹配。迁移产品后,我已经完成了此步骤,并将注册电子邮件作为迁移的前提条件。
-
我可能不清楚。我没有现有用户。我希望用户ID来自通过oauth2的Openid Connect。让我们说这样的情况:1.)用户向我的REST API请求/ api / login 2.)我重定向到OpenID / Oauth2端点进行身份验证3.)我获得令牌ID /访问ID。我从令牌ID甚至电子邮件中获得了UID。 4.)我将访问令牌作为API响应返回给用户。5.)用户请求/ api / some / resource with Bearer:6.)我的REST API接收到对带有访问令牌的/ api / some / resource的请求。在最后一步中,6.如何将访问令牌映射到用户?
-
您的API需要执行以下操作:1.首先验证令牌。然后2.读取令牌的唯一用户ID(通常为\\'sub \\'声明)。然后3.在您的API数据库的"用户"表中查找该用户ID。然后是4a。如果找到,则查找用户的权限。如果未找到,则4b使用默认权限将新行插入到用户表中。然后,5.运行API授权以强制执行权限。
-
一个更有趣的问题是如何管理权限以及由谁管理权限。管理员可能需要在用户首次登录之前在您API的数据库中进行设置。如果是这样,则不应允许按上述方式自动创建用户,并且如果未找到令牌中的用户,则您的应用应显示未授权的错误。如果您可以解释权限的设置方式,我可以提供进一步的建议。这不仅仅是一个技术问题-您可能需要设计一个安全的入职流程。
-
我认为"第一用户" /"管理员"的情况不同,但确实非常重要。我可能仍然会误会,所以请忍受。第一个请求,用户登录。我的API服务器获取令牌ID访问令牌。我返回(哪个令牌,访问权或令牌ID?)给用户。对于用户的第二个请求,用户应该给我什么令牌,访问ID或令牌ID?第二个给我用户名,第一个不给我。因此,如果我在数据库中映射子ID(来自令牌ID),则知道请求的对象是数据库中的哪个用户(在令牌ID验证之后)。如果我刚刚获得访问令牌...。
-
...如果我尚未将访问令牌保存到该用户ID(子)的数据库中,我需要询问IDP谁是访问令牌的对象。如果将令牌ID访问令牌保存在数据库中,那么我可以做任何事情,但是出于安全原因,我觉得将令牌保存在数据库中是个坏主意?想一想这种情况,就好像用户只是对我的其余API使用curl一样。
-
您应该只将访问令牌发送到API,然后该API将对其进行验证并提取用户ID-有关示例,请参见我撰写的步骤14。在我的情况下,唯一的用户ID在uid字段中。 id令牌仅用于UI,并且绝对不应发送给API。您绝对不应将令牌存储在数据库中。
-
但是oauth2的访问令牌不包含与用户ID相关的任何内容吗?来自OpenID connect的令牌ID确实包含用户(子)作为唯一标识符,因为它是JWT。我如何从您的访问令牌中获取用户ID?还是您的意思是我应该针对每个请求从IDP请求基于访问令牌的用户ID?
-
为了巩固您的理解,可能值得花一点时间在PC上运行我的第一个教程代码示例-看看它们如何组合在一起。然后,在工作后修改示例以使用您自己的IDP。然后将学到的知识应用于您的实际解决方案。
-
您能否编辑原始帖子以解释客户端如何进行身份验证和获取令牌(流程如何?)。然后发布访问令牌和ID令牌正文。另外,发布您想要获取的示例用户ID。然后,我将更新原始答案。
-
该系统处于设计阶段,因此我没有任何示例。我正在尝试了解如何实现事物。我用自己的思想流程编辑了原始帖子。
-
感谢您更新答案。它确实清除了一切。我的印象是访问令牌只是一个随机令牌,因此他们添加了包含更多信息(如JWT)的OIDC id令牌。但是由于访问令牌包含此信息,因此它确实很有意义。谢谢!