Open Id Connect疑问-Identity Server 4 //如何向特定用户授予具体作用域?

时间:2019-01-02 12:03:53

标签: oauth-2.0 openid identityserver4 openid-connect

阅读Open Id文档后,我有些疑问。任何帮助将不胜感激。

遵循任何 oidc流程,您都将获得一个id_token和一个access_token。

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

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

c)身份服务器4:您定义要保护的资源。它们可以是“身份资源”和“ api资源”。在定义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”的权限?他们正在使用相同的客户端。

非常感谢!

2 个答案:

答案 0 :(得分:1)

  

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

例如,如果可以将用户细分为组织或部门,并且您想在api中添加策略,以仅在用户属于这些细分组之一时才允许访问某些端点-您可以添加自定义声明"organisationid""departmentid”,然后将该声明及其值添加到已发行的令牌中。无论是否适用,这取决于您所遇到的问题,并且有一条细线可能会在authorization内错误地尝试解决authentication的问题。

  

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

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

  

请求:GET / connect / userinfo   授权:承载{access_token}

     

响应:HTTP / 1.1 200 OK   内容类型:application / json   {       “ sub”:“ 248289761001”,       “ name”:“ Bob Smith”,       “ given_name”:“鲍勃”,       “ family_name”:“史密斯”,       “角色”:[           “用户”,           “管理员”       ]}

最后

  

您如何指定哪些用户可以访问特定资源?

最有可能应该通过Authorization解决此问题,这与OAuth2协议或IdentityServer4无关。 Authorization通常根据问题域的需要在每个应用程序中以不同的方式处理。我建议看一下Identity Server创建者的Policy Server。他们有一个精彩的视频,他们在其中深入探讨了这个主题,还提供了解决该问题的产品。

答案 1 :(得分:1)

IdentityServer包含三个部分:

  1. ApiResource配置
  2. IdentityResource配置
  3. 用户信息(声明)

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

虽然IdentityServer即将对用户进行身份验证,但它还包含授权配置。您可以使用诸如PolicyServer之类的方法将身份从IdentityServer中取出,但是对于基本的身份则不必这样做。

有两种类型的用户声明:

  1. 声明用户名,例如姓名,性别,生日等。
  2. 声明对用户的授权,例如角色,employeeId等。

第一组声明是身份令牌的一部分,并向客户介绍用户的身份,其他声明是访问令牌的一部分,并告诉API允许用户执行的操作。

关于身份令牌,您唯一可以依靠的事实是它始终包含sub声明(用户表中的ID)。此处的简短形式是保持令牌较小,因为您只需要声明即可。可以在UserInfo端点处请求其他信息。身份令牌的内容可能有所不同。例如。您可以强制将所有声明添加到第一个令牌(AlwaysIncludeUserClaimsInIdToken)中,以防止进行其他呼叫。

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

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

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

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

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

返回IdentityServer。 IdentityServer的一项重要工作是过滤声明。因为用户可以有很多主张,但是您只在需要它们时才想要它们。因此,每个令牌都会添加请求的声明。

“身份令牌”声明说明了有关用户的信息。但是,更多的是,这些声明并不依赖于上下文。他们永远是真的。您的名字随处可见,生日也一样。请使用IdentityResource表定义范围,例如openid,个人资料,电子邮件。

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

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

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

访问令牌包含来自所请求范围/资源的所有声明。这意味着使用该令牌可以使用该令牌访问资源/范围内的所有api,而不必为每个api获取新的令牌。

这也意味着令牌可能会变得很大。达到极限之前应避免的事情。这就是为什么您不希望令牌具有权限的原因。如果需要权限,则实现自己的授权服务器。

另一方面,您需要权限吗?在给定的设计中,Api(资源)知道允许用户访问的内容,使用策略(各种业务规则)和基于资源的授权。您可以实现一个本地用户表,其中包含有关权限的信息。

此外,您是否真的需要对每个对象都具有CRUD权限?使用策略,您不仅可以比较字符串值,还可以定义更复杂的授权。

对于用户,用户是身份的资源。但是对范围一无所知。因此,您不能将范围绑定到用户。客户端具有作用域,这为api打开了一扇门,但是api决定用户是否实际上具有访问权限。


现在回答您的问题:

a)将来自用户的所有与请求的声明类型匹配的声明添加到访问令牌中。请求的索赔类型取自请求的范围。在其中添加了与所请求范围相关的所有ApiResource声明类型以及所请求范围本身的声明类型。

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

b)通过将范围添加到客户端来请求令牌。默认情况下,添加了openid,配置文件范围。客户端凭据将不会收到身份令牌,并且还有一个附加令牌,即刷新令牌。请注意,此令牌不适用于所有流程。要请求刷新令牌,请添加offline_access范围。您可以在其中使用脱机访问字面量。这是一个令牌,它允许客户端在不需要用户输入的情况下请求新的访问令牌。因此,如果用户处于脱机状态,则该服务仍可以继续。

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

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

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

假设您具有资源“天气”,范围为“ weather.api.full_access”和“ weather.api.read_only”(作为资源“ weather”的一部分)。

请注意,名称“ weather.api.full_access”并没有说明访问级别,只是说明了预期的功能。

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

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

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

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

简而言之,IdentityServer可以全部实现。如果需要权限,请查看策略服务器。