开启Id Connect疑惑-Identity Server 4 // 如何将特定用户授予具体范围?

Open Id Connect Doubts - Identity Server 4 // How to grant specific users to concrete scopes?

看完Open Id文档后我有些疑惑。任何帮助将不胜感激。

遵循任何 oidc 流程,您最终会得到一个 id_token 和一个 access_token。

a) 当您将 access_token 发送到受保护的 api 时,为什么或何时(示例)它需要检索关于拥有它的用户的一些声明?也许如果受保护的 api 想要使用一些关于经过身份验证的用户的数据?

b) 为了获得声明,受保护的 api 将需要与 UserEdnpoint 端点通信? 它发送 access_token? 返回的 id_token 中包含哪些声明?/如果它要求更多关于用户具有同意访问权限的声明,会发生什么?

c)身份服务器4:您定义要保护的资源。它们可以是 "identity resources" 和 "api resources"。在定义 ApiResources 时,您可以在细粒度范围内定义。例如:

  Scopes =
        {
            new Scope()
            {
                Name = "weather.api.full_access",
                DisplayName = "Full access to WEATHER API",
            },
            new Scope
            {
                Name = "weather.api.read_only",
                DisplayName = "Read only access to WEATHER API"
            }
        }

您还可以定义客户,以及他们可以访问的范围。 您如何指定哪些用户可以访问特定资源?我看不出您将如何映射使用同一客户端的用户的特定权限。

步骤为:

  1. 授予客户端访问两个范围的权限:"weather.api.full_access"、"weather.api.read_only"
  2. 现在....我如何授予 "Billy" 有 "weather.api.full_access" 和 "Jhon" 有 "weather.api.read_only" ?他们使用的是同一个客户端。

非常感谢!!

a)When you send the access_token to a protected api, why or when (example) it would need to retrieve some claims about the user who owns it? Maybe if the protected api wants to use some data about the authenticated user?

例如,如果您的用户可以细分为组织或部门,并且您想在 api 中添加一项策略,以便仅当用户属于这些细分组之一时才允许访问某些端点- 您可以添加自定义声明 "organisationid""departmentid" 并将该声明及其值添加到已发布的令牌中。这是否适用,将取决于您的问题的上下文当 authorization 的问题可能被错误地尝试在 authentication.

内解决时,有一条细线

b) For obtaining the claims the protected api will need to communicate with the UserEdnpoint endpoint? It sends the access_token? And which claims are contained in the returned id_token?/ What happens if it asks for more claims that the user has consent access?

您不一定需要使用 UserInfo 端点。您可以将客户端 属性 AlwaysIncludeUserClaimsInIdToken 设置为 true,默认情况下所有声明都将包含在 id_token 中,因此无需往返 UserInfo 端点。如果您最终选择往返,那么您说需要发送代表用户的 access_token 是正确的,但是,返回的不是 id_token,而是用户信息。 来自 IdentityServer4 docs 的示例:

Request: GET /connect/userinfo Authorization: Bearer {access_token}

Response: HTTP/1.1 200 OK Content-Type: application/json { "sub": "248289761001", "name": "Bob Smith", "given_name": "Bob", "family_name": "Smith", "role": [ "user", "admin" ] }

最后

How do yo you specify which users can access to specific resources?

这应该很可能通过 Authorization 解决,这与 OAuth2 协议或 IdentityServer4 无关。 Authorization 通常根据问题领域的需要在每个应用程序中以不同方式处理。我建议看看 Identity Server 的创建者 Policy Server。他们有一个很好的视频,他们深入研究了这个主题,他们也有一个产品来解决这个问题。

IdentityServer 分为三部分:

  1. Api资源配置
  2. IdentityResource 配置
  3. 用户信息(声明)

有两种令牌:访问令牌和身份令牌。访问令牌用于访问资源(api 以及 UserInfo 端点),身份令牌包含有关用户的信息。

虽然IdentityServer是关于用户认证的,但它也包含授权配置。您可以使用类似 PolicyServer 的东西从 IdentityServer 中获取授权,但对于基本授权,您不必这样做。

有两种类型的用户声明:

  1. 声明用户是谁,例如姓名、性别、生日等
  2. 关于用户被授权的内容的声明,例如角色、employeeId 等

第一组声明是身份令牌的一部分,告诉客户端用户是谁,其他声明是访问令牌的一部分,告诉 API 允许用户做什么.

关于身份令牌,您唯一可以信赖的是它始终包含 sub 声明(来自用户 table 的 ID)。这里哲学的简短版本是保持令牌小,因为你需要的只是那个声明。可以在 UserInfo 端点请求其他信息。身份令牌的内容可能会有所不同。例如。您可以强制将所有声明添加到第一个令牌 (AlwaysIncludeUserClaimsInIdToken),以防止再次调用。

另一方面,如果用户选择不同意,则身份令牌将保持为空(sub 声明除外,因为 scope=openid 是必需的)。同样在从 UserInfo 端点请求时。

所以问题是,您将如何使用身份令牌?令牌有多少价值?您不应该使用它来访问资源(这是访问令牌的用途)并且它可能不包含请求的信息。

关于访问令牌,这是实际使客户端能够访问资源的令牌 (api)。在 client_credentials 流程中,没有用户(因此也不会有身份令牌),而在其他 flwos 中,客户端将代表用户进行操作。第一个流与其他流之间的区别在于 sub 声明。这告诉 Api 代表谁代表客户端请求访问。

访问令牌计数相同,如果用户不同意,则客户端将无法访问资源。

关于资源和范围。资源是资源的逻辑名称。我的意思是您可能有多个 Api 是同一资源的一部分。没关系。因为一个资源可以有多个作用域。在示例中它是 1:1,但是当您真正使用范围​​时,您会看到范围实际上定义了资源中的特定功能。喜欢微服务。

回到身份服务器。 IdentityServer 的一个重要工作是过滤声明。因为用户可以有很多 claims,但是你只在需要的时候才想要它们。因此,每个标记都会添加请求的声明。

Identity Token 声明说明了用户是谁。但还有更多,这些声明不依赖于上下文。他们永远是真的。你的名字到处都是一样的,你的生日也是如此。使用 IdentityResource table 来定义范围,例如openid、个人资料、电子邮件。

访问令牌中的声明依赖于上下文。因为只有 API 才知道声明的含义。使用命名空间类型来区分声明。

Api 资源的设置方式并不重要,只要记住,当请求一个范围时,该资源的所有声明(包括该资源中的其他范围)都会添加到请求过滤器中,而当请求一个范围时,只有该范围的声明被添加到请求过滤器中。用于将用户的所有匹配声明添加到令牌的请求过滤器。

现在你有了一个访问令牌。令牌必须包含有关范围的信息。为什么?因为您不希望客户端访问不允许的资源。通过定义每个客户端的范围来限制访问。由于范围是一项功能,您知道客户需要哪些范围。在 IdentityServer 中,您配置相同的范围以匹配客户端。永远不要相信客户。

访问令牌包含请求的 scope/resources 中的所有声明。这意味着使用该令牌可以使用该令牌访问 resource/scope 中的所有 api,而无需为每个 api.

获取新令牌

这也意味着令牌可以变得相当大。在达到极限之前你应该避免的事情。这就是为什么您不想要令牌中的权限。如果你想要权限,那么实现你自己的授权服务器。

另一方面,你需要权限吗?给定 Api(资源)知道允许用户访问什么的设计,使用策略(某种业务规则)和基于资源的授权。您可以实现包含权限信息的本地用户 table。

另外,你真的需要每个对象的 CRUD 权限吗?通过策略,您有机会定义比仅仅比较字符串值更复杂的授权。

对于用户来说,用户就是身份的资源。但对作用域一无所知。所以你不能将范围绑定到用户。客户端有作用域,这为 api 打开了大门,但 api 决定了用户是否真的有访问权限。


现在回答您的问题:

a) 用户的所有与请求的声明类型相匹配的声明都将添加到访问令牌中。请求的声明类型取自请求的范围。添加与请求范围相关的所有 Api 资源声明类型以及请求范围本身的声明类型。

如果 Api 需要有关用户的信息,则它可以使用访问令牌来调用 UserInfo 端点。默认身份令牌仅包含 sub 声明(用户无法拒绝或撤销)。

b) 通过向客户端添加范围来请求令牌。默认情况下会添加 openid、配置文件范围。客户端凭据将不会收到身份令牌,并且还有一个额外的令牌,即刷新令牌。请注意,此令牌并非对所有流程都可用。要请求刷新令牌,请添加 offline_access 范围。您可以在哪里进行离线访问文字。这是一个允许客户端请求新访问令牌的令牌,无需用户输入。所以在用户离线的情况下,服务仍然可以继续。

当需要用户同意时,某些信息或选项可能不可用。例如。如果用户不希望离线访问,则该服务(例如某些同步服务)将无法 运行。当用户撤销给定的同意时也会发生这种情况。请求新的访问令牌将导致未经授权的响应。

为了绕过丢失的用户信息,只需向用户询问信息并将其存储在本地即可。无论如何,您很可能在那里需要它。

c) 忘记权限,使用策略和基于资源的授权。在 Api 中实现它。那是确切上下文已知的地方。客户端可以打开api的门,但是否可以访问资源取决于用户(声明,本地授权信息)。

假设您有资源 'weather' 和范围 'weather.api.full_access' 和 'weather.api.read_only'(作为资源 'weather' 的一部分)。

请注意,名称 'weather.api.full_access' 并未说明访问级别,仅说明预期的功能。

实际访问级别应基于资源或政策的本地信息,例如用户具有读取订阅或管理员角色。

为了授予 Billy 完全访问权限,请向 Billy 添加 http://api/admin(值:true)声明。对于 Jhon,在订阅中添加一条记录 table。

为了将资源划分为多个 api(每个范围),使用事件来验证范围。您不希望客户端在仅请求读取范围时访问 full_access 功能。

我希望这对你有意义。很难给出一个简短而完整的答案。如果您对此答案有疑问,请告诉我。

总之IdentityServer都能实现。如果您需要权限,请查看策略服务器。