Ocelot,Identity,IdentityServer4和API资源,如何基于角色授予访问权限

问题描述

我正在尝试学习采用网络核心的微服务方法。因此,经过大量的教程,这是我到目前为止所掌握的:

  1. 我创建了两个API项目:Company和Package。端口5002和5010

  2. 我需要一个网关,Ocelot是一个我有这个配置:

{

  "Routes": [
    // Company Api
    {
      "DownstreamPathTemplate": "/api/company/{everything}","DownstreamScheme": "http","DownstreamHostAndPorts": [
        {
          "Host": "localhost","Port": 5002
        }
      ],"UpstreamPathTemplate": "/api/company/{everything}","UpstreamHttpMethod": [
        "GET"
      ],"Authenticationoptions": {
        "AuthenticationProviderKey": "TestKey","AllowedScopes": []
      },"AddHeadersToRequest": {
        "CustomerId": "Cla@R_404_6424@[sub] > value"
      }
    },// Anonymous Company Api
    {
      "DownstreamPathTemplate": "/api/company/getHomeSections","UpstreamPathTemplate": "/api/anonymous/company/getHomeSections","UpstreamHttpMethod": [
        "GET"
      ]
    },// Package Api
    {
      "DownstreamPathTemplate": "/api/package/{everything}","Port": 5010
        }
      ],"UpstreamPathTemplate": "/api/package/{everything}","AllowedScopes": []
      }
    }
  ],"GlobalConfiguration": {
    "BaseUrl": "http://localhost:5000"
  },"AllowedHosts": "*"
}
  1. 我有一个配置了identity和mongoDB的identityServer4。就像魅力一样。

我已在angular 10中配置了一个客户端。我可以登录,获得令牌,一切正常。

现在我的大问题是,如何基于API /角色授予用户访问权限?因此,假设角色A有权访问公司/读取,而角色B可以访问公司/读取和公司/写入?

实际上是如何实现的?

非常感谢。

解决方法

如何基于API /角色授予用户访问权限?

有两种方法:

在客户端上

此方法完全不涉及网关,仅涉及IdentityServer。

如果您只希望在UX中基于角色的行为-允许/禁止某些调用或隐藏/显示某些屏幕/组件,则可以执行以下操作:

  1. 根据用户在Identity Server中的要求对角色进行建模
  2. 让UX询问登录时返回的承载JWT并解压缩索赔集合
  3. 基于发现的角色应用基于角色的UX逻辑。

在网关中/在后端

这更加复杂,但是如果您希望后端具有基于角色的行为,则需要在服务中对此进行编码。例如,一种实现方法是让每个服务接受一组角色作为标头参数。然后您可以:

  1. 根据用户在Identity Server中的要求对角色进行建模
  2. 在Ocelot中公开没有任何角色标头参数的上游服务路径
  3. 当UX发出请求时,让Ocelot将“角色”声明作为下游http头注入(与您当前对customerId的处理方式相同)
  4. 然后,您可以让每个服务根据角色来决定是否允许请求

但是,这感觉很笨拙。在服务级别上考虑访问控制时,角色感觉有点太粗糙了。

也许是第三种方式...

因此,基于角色的行为在您的前端运行良好,但是您的后端呢?

由于您已经利用了将CustomerId用户声明注入下游服务的功能,因此我们应该考虑另一种解决方案。

为什么不在后端使用基于角色的行为,而不是仅使用资源标识符来控制访问?例如,可以使用customerId作为路径的一部分来定义与客户有关的私有http操作:

GET /customers/{customerId}

在Ocelot中,上游路径可以显示为

GET /customers

当在网关上接收到请求时,customerId声明将注入到下游路径中(注意:Ocelot不支持现成的路径参数注入。您需要创建派生自{{3}的类},并将其与ocelot.json中的DelegatingHandlers[]集合一起使用来进行DelegatingHandler)。

同样,您可以通过创建从GET /companyGET /company/{companyId}的Ocelot路由来保护公司API,其中companyId是用户声明。

结合前端的基于角色的行为,与基于角色的行为相比,此方法可为您在网关/后端提供更细粒度的访问控制。您将两全其美。