问题描述
我正在尝试学习采用网络核心的微服务方法。因此,经过大量的教程,这是我到目前为止所掌握的:
{
"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": "*"
}
我已在angular 10中配置了一个客户端。我可以登录,获得令牌,一切正常。
现在我的大问题是,如何基于API /角色授予用户访问权限?因此,假设角色A有权访问公司/读取,而角色B可以访问公司/读取和公司/写入?
实际上是如何实现的?
非常感谢。
解决方法
如何基于API /角色授予用户访问权限?
有两种方法:
在客户端上
此方法完全不涉及网关,仅涉及IdentityServer。
如果您只希望在UX中基于角色的行为-允许/禁止某些调用或隐藏/显示某些屏幕/组件,则可以执行以下操作:
- 根据用户在Identity Server中的要求对角色进行建模
- 让UX询问登录时返回的承载JWT并解压缩索赔集合
- 基于发现的角色应用基于角色的UX逻辑。
在网关中/在后端
这更加复杂,但是如果您希望后端具有基于角色的行为,则需要在服务中对此进行编码。例如,一种实现方法是让每个服务接受一组角色作为标头参数。然后您可以:
- 根据用户在Identity Server中的要求对角色进行建模
- 在Ocelot中公开没有任何角色标头参数的上游服务路径
- 当UX发出请求时,让Ocelot将“角色”声明作为下游http头注入(与您当前对customerId的处理方式相同)
- 然后,您可以让每个服务根据角色来决定是否允许请求
但是,这感觉很笨拙。在服务级别上考虑访问控制时,角色感觉有点太粗糙了。
也许是第三种方式...
因此,基于角色的行为在您的前端运行良好,但是您的后端呢?
由于您已经利用了将CustomerId用户声明注入下游服务的功能,因此我们应该考虑另一种解决方案。
为什么不在后端使用基于角色的行为,而不是仅使用资源标识符来控制访问?例如,可以使用customerId作为路径的一部分来定义与客户有关的私有http操作:
GET /customers/{customerId}
在Ocelot中,上游路径可以显示为
GET /customers
当在网关上接收到请求时,customerId声明将注入到下游路径中(注意:Ocelot不支持现成的路径参数注入。您需要创建派生自{{3}的类},并将其与ocelot.json中的DelegatingHandlers[]
集合一起使用来进行DelegatingHandler)。
同样,您可以通过创建从GET /company
到GET /company/{companyId}
的Ocelot路由来保护公司API,其中companyId是用户声明。
结合前端的基于角色的行为,与基于角色的行为相比,此方法可为您在网关/后端提供更细粒度的访问控制。您将两全其美。