Ocelot、Identity、IdentityServer4 和 API 资源,如何根据角色授予访问权限
Ocelot, Identity, IdentityServer4 and API Resource, how to grant access on a role basis
我正在尝试了解使用 net core 的微服务方法应该如何。所以在学习了很多教程之后,这就是我到目前为止所得到的:
我创建了两个api项目:Company和Package。端口 5002 和 5010
我需要一个网关,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": "*"
}
- 我有一个配置了身份和 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,您可以执行以下操作:
- 将您的角色建模为 Identity Server 中的用户声明
- 让 UX 询问登录时返回的承载 JWT 并解压缩声明 collection
- 根据发现的角色应用您的 role-based UX 逻辑。
在gateway/onback-end
这比较复杂,但如果您想在 back-end 中有 role-based 行为,则需要在您的服务中为其编写代码。例如,一种方法是让每个服务接受 collection 个角色作为 header 参数。那么你可以:
- 将您的角色建模为 Identity Server 中的用户声明
- 在 Ocelot 中不带任何角色公开上游服务路径header参数
- 当 UX 发出请求时,让 Ocelot 将“角色”声明作为下游 http header(与您当前对 customerId 的处理方式相同)
- 然后你可以让每个服务根据角色决定是否允许请求
然而,这感觉很笨拙。想想 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 /company
到 GET /company/{companyId}
的 Ocelot 路由来保护您的公司 API,其中 companyId 是用户声明。
结合 front-end 上的 role-based 行为,此方法为您 gateway/back-end 提供了比 role-based 更多的 finer-grained 访问控制行为。您可以两全其美。
我正在尝试了解使用 net core 的微服务方法应该如何。所以在学习了很多教程之后,这就是我到目前为止所得到的:
我创建了两个api项目:Company和Package。端口 5002 和 5010
我需要一个网关,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": "*"
}
- 我有一个配置了身份和 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,您可以执行以下操作:
- 将您的角色建模为 Identity Server 中的用户声明
- 让 UX 询问登录时返回的承载 JWT 并解压缩声明 collection
- 根据发现的角色应用您的 role-based UX 逻辑。
在gateway/onback-end
这比较复杂,但如果您想在 back-end 中有 role-based 行为,则需要在您的服务中为其编写代码。例如,一种方法是让每个服务接受 collection 个角色作为 header 参数。那么你可以:
- 将您的角色建模为 Identity Server 中的用户声明
- 在 Ocelot 中不带任何角色公开上游服务路径header参数
- 当 UX 发出请求时,让 Ocelot 将“角色”声明作为下游 http header(与您当前对 customerId 的处理方式相同)
- 然后你可以让每个服务根据角色决定是否允许请求
然而,这感觉很笨拙。想想 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 /company
到 GET /company/{companyId}
的 Ocelot 路由来保护您的公司 API,其中 companyId 是用户声明。
结合 front-end 上的 role-based 行为,此方法为您 gateway/back-end 提供了比 role-based 更多的 finer-grained 访问控制行为。您可以两全其美。