IdentityServer4中API资源与API范围中的用户声明是什么?

19

我已经配置了IdentityServer4的实例,并成功地将其配置为OIDC提供程序的客户端。现在我正在尝试将其设置为我的应用程序的OIDC提供程序。我按照快速入门和文档进行了操作,但我很难找到对我的具体问题的答案。

用户声明可以在几个不同的位置指定:API资源和API作用域。在API资源和该资源的API作用域上指定用户声明有什么区别?

我对术语的理解是:

  • API资源表示客户端将访问的API,例如 "GitHub API",我的 "数据导入API"
  • API范围表示API中的资源子集,客户端可以请求访问这些资源,例如 repo => 公共和私有存储库,import_job:control => 启动/停止/删除导入作业
  • 用户声明是关于用户的信息片段,例如 email => 电子邮件地址

将用户声明与API资源和/或作用域关联一定是有意义的,但我无法进行精神飞跃以确定为什么以及如何关联。请在上述上下文中提供这些声明的说明性示例:GitHub API(假设没有定义任何内容)和通用批量导入API。


答案:
我已配置IdentityServer4的实例,并成功地将其配置为OIDC提供程序的客户端。现在我正在尝试将其设置为我的应用程序的OIDC提供程序。我按照快速入门和文档进行了操作,但我很难找到对我的具体问题的答案。
用户声明可以在几个不同的位置指定:API资源和API作用域。在API资源和该资源的API作用域上指定用户声明有什么区别?
我对术语的理解是:
- API资源表示客户端将访问的API,例如 "GitHub API",我的 "数据导入API" - API范围表示API中的资源子集,客户端可以请求访问这些资源,例如 repo => 公共和私有存储库,import_job:control => 启动/停止/删除导入作业 - 用户声明是关于用户的信息片段,例如 email => 电子邮件地址
将用户声明与API资源和/或作用域关联一定是有意义的,以下是说明性示例:
- 对于GitHub API,可能会定义一个名为profile的API资源,它代表GitHub用户资料。在此API资源上,可能会指定用户声明nameblog,分别代表用户的名称和博客URL。 - 对于批量导入API,可能会定义一个名为batch的API资源,它代表批次导入任务。在此API资源上,可以指定用户声明job_title,表示批次导入任务所属的工作职称。
因此,API资源和API作用域上的用户声明可以为客户端提供有关所请求访问的资源和数据的额外信息。
3个回答

29
一个资源是一个可以分为逻辑部分(作用域)的概念,可以以各种方式实现。无论如何,虽然这可能在文档中不太明显,但对于IdentityServer来说,一个资源至少有一个作用域。
为了允许客户端访问资源,必须配置客户端允许使用哪些作用域。在示例中,作用域的名称与资源的名称相同,但实际上一个资源可能有多个作用域。请注意,只允许使用一个作用域的客户端可以访问整个资源(受众),除非资源(API)基于允许的作用域筛选访问权限(作用域是作为作用域声明的一部分包含在访问令牌中)。
IdentityServer的一个特点是它是一个令牌提供程序,例如访问令牌和标识令牌。
从最后一个开始,有两种类型的标识令牌。有一个'最小'的身份令牌(仅包含'sub'声明),仅在请求访问令牌时发出。还有一个'完整'的身份令牌,客户端可以在UserInfo端点请求。
对于IdentityServer,用户声明是一个(身份信息)资源。顺便说一下,在使用此信息之前应该要求用户同意,因为用户拥有此信息。

并非所有用户声明都需要加入到请求UserInfo端点的身份令牌中。为了确定应该包含哪些声明,IdentityServer会查看Identity ~表。根据这些表,可在UserInfo上下文中使用已请求Claim集合来过滤用户声明资源。

换句话说,当客户端配置为请求“openid”作用域时,仅包括“sub”声明,在添加“profile”作用域时,将包括底层的个人资料声明(如果在UserClaims表中可用),并配置“email”作用域将把电子邮件地址添加到身份令牌中。

对于访问令牌,有一个类似的机制。基于ApiClaims和ApiScopeClaims表,授权上下文中提供了一个RequestedClaims集合。有关更多信息,请参见我的答案

假设要将“name”声明添加到访问令牌中,则将其添加到其中一个表中。有关附加信息,请参见 我的答案 或实际上整个线程。

尽管在IdentityServer中添加各种声明到访问令牌是可能的,但你应该考虑这是否是正确的方法,正如这篇文章所解释的那样。
访问令牌声明的问题在于这些声明用于用户授权。但用户声明通常不适用于用户授权。而且你不想最终只得到一个包含所有声明的超级访问令牌。
回过头来看,IdentityServer的目的是配置资源保护和客户端授权。客户端可以连接到一个资源(范围),但是被授权访问信息的是用户:客户端的请求始终是“代表用户”的。这就是为什么在交互式流程中,“sub”声明始终是访问令牌的一部分。此外,IdentityServer可以扩展以处理用户身份验证。但是,尽管在当前设计中是可能的,用户授权不再是IdentityServer的关注点。
IdentityServer的创建者曾经思考过用户授权的问题,并提出了一个单独的服务: PolicyServer,将授权声明从IdentityServer和访问令牌中取出。因此,为了回答你的问题,不同的表用于配置资源、范围、客户端和过滤器,这些都用于构建令牌。用户声明告诉我们一些关于用户(身份)的信息,并且不在访问令牌中。
对于用户授权,我可以推荐使用类似 PolicyServer 服务器的实现,结合基于资源的授权。
以下是各个表的简要概述:
- AspNetUserClaims - 用户信息资源 - ApiResources - 资源的名称 - ApiScopes - 许多作为资源一部分的范围 - IdentityResources - 实际上是身份的作用域(例如 openid profile) - IdentityClaims - 过滤 AspNetUserClaims 以获得身份令牌 - ApiClaims - 过滤 AspNetUserClaims 以获得访问令牌,无论请求哪个范围 - ApiScopeClaims - 过滤 AspNetUserClaims 以获得访问令牌,取决于所请求的范围 - ClientClaims - 特定客户端包括的声明 - ClientScopes - 客户端允许的范围
客户端请求范围。如果省略了范围,则按规范将所有允许的范围视为已请求。
API 是资源(受众)的一部分。当一个资源有多个范围时,需要更细粒度的基于范围的客户端授权。

用户授权用于确定用户被允许执行什么操作:客户端可以连接到API,由范围(例如日历)进行过滤,并且用户被授权读取但不是写入事件。

尽管calendar.writecalendar.read可以是范围,但与用户授权无关。用户可以被授权读取和写入,但由于客户端可能受限制(例如仅限calendar.read),因此用户可能需要使用不同的客户端才能连接到资源,例如日历应用程序既有电子邮件应用程序calendar.read只有。


非常感谢您提供如此详尽的答案!表格的描述帮助了很多。 - alastairs
3
这是我见过的关于这个主题最完整的解释之一。首先,非常感谢您的努力。我想指出的是,我现在正在设置一个IdentityServer4依赖方,并使用EntityFramework支持持久性,但我找不到任何名为ApiClaimsIdentityClaims的表。另一方面,我浏览了IS4.EF代码,并找到了一个名为UserClaim的类,它被ApiResourceClaimApiScopeClaimIdentityResourceClaim类继承,并且它们一直映射到数据库。 - Sume

5

ApiResource可以包含许多范围(订单、折扣、会计等)。例如,您需要一个令牌才能访问GitHub的个人资料信息,而不是存储库等。在这种情况下,GitHub是一个ApiResource,并包含个人资料范围。

当用户发送请求以获取令牌时,只需指定一些范围(而不是ApiResource),然后IdentityServer将检测用户想要访问哪些ApiResource(从请求的范围中)。

ApiResource中的UserClaims: 当您在ApiResource中指定UserClaims时,当用户请求访问该ApiResource的令牌时,这些UserClaims将包含在令牌中。

范围中没有任何UserClaims。


1
为了回答中提出的基于GitHub的示例,我点赞了。 - alastairs

0

补充一下Mehrdad的回答:

我喜欢把claims看作是API中包含用于标识和授权的字段的对象。

其中一些claims将来自OAuth访问令牌中的信息,但claims信息也可以来自其他地方。

我的文章可能会帮助您更直观地理解这个概念。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接