Ocelot、Identity、IdentityServer4 和 API 资源,如何根据角色授予访问权限

Ocelot, Identity, IdentityServer4 and API Resource, how to grant access on a role basis

我正在尝试了解使用 net core 的微服务方法应该如何。所以在学习了很多教程之后,这就是我到目前为止所得到的:

  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": "Claims[sub] > value"
      }
    },
    // Anonymous Company Api
    {
      "DownstreamPathTemplate": "/api/company/getHomeSections",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5002
        }
      ],
      "UpstreamPathTemplate": "/api/anonymous/company/getHomeSections",
      "UpstreamHttpMethod": [
        "GET"
      ]
    },
    // Package Api
    {
      "DownstreamPathTemplate": "/api/package/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5010
        }
      ],
      "UpstreamPathTemplate": "/api/package/{everything}",
      "UpstreamHttpMethod": [
        "GET"
      ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "TestKey",
        "AllowedScopes": []
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:5000"
  },
  "AllowedHosts": "*"
}
  1. 我有一个配置了身份和 mongoDB 的 identityServer4。很有魅力。

我在 angular 10 中配置了一个客户端。我可以登录,我得到了令牌,一切都按预期工作。

现在我的大问题是,如何根据 API / 角色授予用户访问权限?假设角色 A 可以访问 company/read,角色 B 可以访问 company/read 和 company/write?

实际如何实现?

非常感谢。

how do I grant access to users on a API / Role basis?

有两种方法:

客户端上

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

如果您只想 role-based UX 中的行为 - allow/disallow 某些调用或 hide/show 某些 screens/components,您可以执行以下操作:

  1. 将您的角色建模为 Identity Server 中的用户声明
  2. 让 UX 询问登录时返回的承载 JWT 并解压缩声明 collection
  3. 根据发现的角色应用您的 role-based UX 逻辑。

在gateway/onback-end

这比较复杂,但如果您想在 back-end 中有 role-based 行为,则需要在您的服务中为其编写代码。例如,一种方法是让每个服务接受 collection 个角色作为 header 参数。那么你可以:

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

然而,这感觉很笨拙。想想 service-level 的访问控制,角色感觉有点太 coarse-grained.

也许还有第三种方式...

所以,role-based 行为在你的 front-end 上运行良好,但是你的 back-end 呢?

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

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

GET /customers/{customerId}

在Ocelot中,上游路径可以暴露为

GET /customers

customerId声明在网关收到请求时注入到下游路径(注意:Ocelot不支持路径参数注入out-of-the-box。需要创建一个class派生自DelegatingHandler, and use it with the DelegatingHandlers[] collection in the ocelot.json to do this).

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

结合 front-end 上的 role-based 行为,此方法为您 gateway/back-end 提供了比 role-based 更多的 finer-grained 访问控制行为。您可以两全其美。