c# - IdentityServer4:数据库中不同表中的不同用户类型
问题描述
当前情况:我有一个包含 3 个 WebAPI 项目的应用程序(比如说 API A、B、C)。每个都有基于令牌的身份验证(基于 OAuthAuthorizationServerProvider)。有 3 种用户类型(假设类型 1、2、3)。每个用户类型存储在单独的数据库表中;
- 移动客户端(“类型 1”用户)使用的“API A”
- “API B”部分由移动客户端(“类型 1”用户)使用,部分由 Web 客户端(角度应用程序,“类型 2”用户)使用
- Web 客户端使用的“API C”(“类型 3”用户)
还,
- “类型 1”用户可以从“API A”获取令牌并将其交换为来自“API B”的另一个令牌,以便访问“API B”资源(“类型 1”用户使用的“API B”中的一些控制器,其他 - 由“类型 2”用户)
- “类型 2”用户有两步授权
- 他们使用登录名和密码来获取对单个控制器具有“限制访问”的令牌,以便从中选择一些值
- 使用之前的令牌和选择的值,他们将其交换为“完全访问”令牌
我打算从当前的授权方案迁移到 IdentityServer4。所以,我有几个问题:
主要问题:
- 如何通过具有单个 IdentityServer4 实例的单个端点(服务器/连接/令牌)在 3 个不同的数据库表中验证 3 个不同的用户类型?
附加问题:
- 如何为“Type 2”用户实施两步授权?
- 你对我的情况有什么建议?
谢谢!
解决方案
对于 IdentityServer,只有一种类型的用户需要进行身份验证。所以所有用户都应该移动到同一张表(如何迁移是另一个问题)。如果将用户移动到一个表是一个问题,那么 IdentityServer 可能不是实现安全性的正确工具。尽管可以通过实现自定义用户存储来维护单独的表。每个用户可以启用两因素身份验证。您可以使用扩展授权来实施自定义授权。
安全性的全部目的是保护您的资源:api。在 IdentityServer 中,资源名称是功能的逻辑名称,可以拆分为多个范围,其中范围是特定功能。
Api1
可以是具有多个作用域的资源(例如Api1.Read
and Api1.Write
)或只是Api1
. 但是Api1
,Api2
andApi3
也可以是Api
资源的一部分,其中Api1
,Api2
andApi3
实际上是作用域。在您的情况下Api1
,可能是具有as范围的资源。Api1
为了使用户能够访问资源,您需要一个客户端应用程序,尽管您可以拥有许多可以访问同一资源的客户端。为了支持不同类型的客户端,可以选择多种授权类型。
IdentityServer 允许您配置完整的图片。
假设有一个客户端可以访问不同的 Api,其中每个 Api 都是一个资源/范围。
需要允许客户端代表用户访问 Api ,因为没有用户,客户端无法访问资源。
所以应该允许客户端使用某些范围,这些范围需要客户端请求。没有这个,客户端就无法访问资源。假设客户端配置为Api1
和Api2
,但仅Api1
由客户端请求。然后Api2
和Api3
不可达。
这都是顶层授权的一部分。现在是时候让用户参与进来了。当客户端访问 api 时,api 知道哪个用户发出了请求(作为sub
访问令牌的一部分)。但这还不足以授予或拒绝访问权限。
所以你需要一些东西来授权用户。关于如何实现这一点有很多选择。看看文档。
考虑一个简单的实现,其中有三个策略。并且每个策略都确保只有匹配类型的用户才能访问。
那么实际的问题是,如何区分用户类型呢?
您可以在UserClaims表中添加声明。假设ClaimType是UserType
并且value是1
。在资源中添加一个检查声明UserType
和所需值的策略。
为了让 IdentityServer 将声明添加到访问令牌,请确保声明类型是范围的一部分(或在配置了多个范围并需要声明类型时为 ApiResource)。
通过将claimType添加UserType
到Api_
范围,意味着在访问范围时,必须包含声明。IdentityServer 尝试通过仅过滤请求的声明来限制访问令牌中的声明数量。
当用户访问 Api_ 时,声明应该是访问令牌的一部分(假设声明是为每个用户设置的,否则用户根本没有访问权限)。您可以为其他 api(范围)重复此设置。
在这种情况下,我认为这是一个可以接受的解决方案。其他选项是较低级别的授权(基于资源)或外包,例如PolicyServer。
请注意,由于 SSO,用户也有可能通过其他客户端的身份验证。但由于仅授予某些类型的用户访问权限(作为策略的一部分),您可以阻止其他类型的用户访问不适合他们的资源。您可以通过禁用自动登录来防止这种行为。
推荐阅读
- apache-spark - Spark Job 生成的文件数
- python - 如何正确地将这个 for 循环集成到我的程序中?
- sql - 如何显示最多参加会议的两个人的姓名和职务
- python - 如何循环遍历 TCL 中的向量?
- python - Scrapy 不关注域中的链接
- fiware - 如何更新 OrionLD (mongoDB) 中缓存的上下文?
- python-3.x - 在另一个视图中调用 Django Rest Framework 视图
- java - 如何检查 DES/CBC/NoPadding 解密的密钥不正确?
- ruby-on-rails - Ruby on Rails 使用 gem 'iex-ruby-client'
- kotlin - 如何在 Kotlin Desktop Compose 中触发 PC 键盘输入