1

我正在尝试学习使用 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 可以访问公司/读取,而角色 B 可以访问公司/读取和公司/写入?

如何实际实现这一目标?

非常感谢。

4

1 回答 1

1

如何基于 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 不支持开箱即用的路径参数注入。您需要创建一个派生自DelegatingHandler的类,并将其与DelegatingHandlers[]ocelot.json 中的集合来执行操作)。

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

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

于 2020-09-07T22:07:34.193 回答