基于声明的授权是否适用于单个资源
Is claims based authorization appropriate for individual resources
我了解对我通常称为 "roles" 或 "permissions" 的事物的声明的用法。我知道声明更笼统,但根据我在实践中看到的情况,通常可以归结为:如果用户拥有这组声明,他们就可以访问某些区域,或执行某些功能。
想象一个 wiki 应用程序。您可能有一个允许用户添加内容的 content_contributor 声明,一个允许用户添加内容的 content_admin 声明用户删除内容,以及允许将贡献者权利授予其他用户的 modify_user 声明。
将此示例更进一步,我可能想限制用户,以便他们只能看到由他们自己或他们的团队创建的内容。
如果用户只能看到自己创建的内容,我们是否会对他们创建的每条内容都拥有所有权,或者我们是否会将授权委托给应用程序?
当您谈论 角色 和 权限 时,您就是在谈论 授权。
对于授权,声明通常不是。 (Identity)声明是为了模拟用户的 identity:who 是用户?声明本身并没有说明任何有关授权的信息。用户可以拥有角色声明,但这不会告诉应用程序允许用户做什么。
授权由应用程序根据用户身份完成。将授权视为一组 规则集 ,例如:
18+:允许用户年满 18 岁(DateOfBirth)。
使用汽车: 当用户有驾照时允许。
或者类似的东西。
角色有点混乱,因为它们经常被误用于授权。请阅读 this article 了解一些背景信息。
IMO 角色的问题在于它们并不通用。我可以在一家医院当 医生,而在另一家医院当 病人。我可以是一个租户的 Admin,但另一个租户的 User。所以它们只有在特定的上下文中才有意义。
将角色包含在声明中的唯一原因是您不需要查找此信息,因为它已经存在。但是鉴于前面的评论,您实际上不能包含此信息。当你这样做时,它只会让你头疼。因为在用户再次登录之前,您无法执行更新或更改权限或配置文件设置等简单操作。
因此,作为一条经验法则:让授权靠近资源(api / 网站)。因为那是执行业务规则的地方。这是您可以存储和更新权限等的地方
在身份验证和授权方面保持关注的分离。身份验证告诉您用户是谁,授权告诉您允许用户做什么。不要混用这两个。
将其翻译成您的 wiki 应用程序:
创建一个单独的上下文,您可以在其中存储角色和权限等授权信息。您可以在中央资源(针对多个应用程序)中管理它或在您的应用程序中使用上下文。我不会将此上下文与 业务上下文 .
混合
在授权上下文中添加一个用户并添加一个角色content_contributor。在应用程序中读取该用户的权限(从中央 API、本地授权上下文、设置文件或任何最适合的内容)(基于 sub 声明).缓存它以加快性能,并应用规则来确定用户是否被允许访问该资源。
您可以使用 resource-based authorization 扩展它。将 sub 声明的值保存在内容记录中以标识所有者。当当前用户匹配 sub 声明值时,当前用户就是所有者。
您可以对团队使用相同的方法。将 teams table 添加到 业务上下文 并将用户 link 添加到一个或多个团队。直接使用 sub 声明值或间接使用用户 table,也在业务上下文中,用户被 linked 到 sub 声明价值。如果您想显示此信息(如在报告中),您可以添加姓名等。
您可以保存团队ID和/或用户ID或sub声明值( owner 是内容记录中与当前用户同属一个团队的成员)以确定允许的用户访问权限。
我的设置是这样的:
身份上下文:用户 + 用户声明。仅用于身份验证。独立于应用程序。
授权上下文:用户(id = 子声明)+ 每个应用程序:角色、权限等。在单独的 'local' 数据库或中央数据库中。仅供授权。
业务上下文:用户(Id、名称、'foreign key' 子声明,没有实际的数据库关系,因为 table 在上下文之外)+团队、个人资料、设置等。当用户 table 被省略时,链接到 sub 声明值。
为了使业务上下文中的用户 table 保持最新,请定期刷新这些值。例如,您可以在用户 x 时间后登录时更新值。或者偶尔查询身份上下文(使用 API)以请求用户信息(使用身份用户信息端点)。
在所有上下文中都可以有一个 users table,但它们都有不同的含义并包含其他信息。所以没有冗余信息。
授权发生在应用程序内部,并基于授权上下文中的业务规则(策略)和授权信息。
最后一点,当当前系统需要角色声明时(例如 User.IsInRole()
或 [Authorize("role")]
),您可以在每次调用时(从缓存中)读取角色/权限并添加这些到当前用户的声明集合(声明转换)。
我了解对我通常称为 "roles" 或 "permissions" 的事物的声明的用法。我知道声明更笼统,但根据我在实践中看到的情况,通常可以归结为:如果用户拥有这组声明,他们就可以访问某些区域,或执行某些功能。
想象一个 wiki 应用程序。您可能有一个允许用户添加内容的 content_contributor 声明,一个允许用户添加内容的 content_admin 声明用户删除内容,以及允许将贡献者权利授予其他用户的 modify_user 声明。
将此示例更进一步,我可能想限制用户,以便他们只能看到由他们自己或他们的团队创建的内容。
如果用户只能看到自己创建的内容,我们是否会对他们创建的每条内容都拥有所有权,或者我们是否会将授权委托给应用程序?
当您谈论 角色 和 权限 时,您就是在谈论 授权。
对于授权,声明通常不是。 (Identity)声明是为了模拟用户的 identity:who 是用户?声明本身并没有说明任何有关授权的信息。用户可以拥有角色声明,但这不会告诉应用程序允许用户做什么。
授权由应用程序根据用户身份完成。将授权视为一组 规则集 ,例如:
18+:允许用户年满 18 岁(DateOfBirth)。
使用汽车: 当用户有驾照时允许。
或者类似的东西。
角色有点混乱,因为它们经常被误用于授权。请阅读 this article 了解一些背景信息。
IMO 角色的问题在于它们并不通用。我可以在一家医院当 医生,而在另一家医院当 病人。我可以是一个租户的 Admin,但另一个租户的 User。所以它们只有在特定的上下文中才有意义。
将角色包含在声明中的唯一原因是您不需要查找此信息,因为它已经存在。但是鉴于前面的评论,您实际上不能包含此信息。当你这样做时,它只会让你头疼。因为在用户再次登录之前,您无法执行更新或更改权限或配置文件设置等简单操作。
因此,作为一条经验法则:让授权靠近资源(api / 网站)。因为那是执行业务规则的地方。这是您可以存储和更新权限等的地方
在身份验证和授权方面保持关注的分离。身份验证告诉您用户是谁,授权告诉您允许用户做什么。不要混用这两个。
将其翻译成您的 wiki 应用程序:
创建一个单独的上下文,您可以在其中存储角色和权限等授权信息。您可以在中央资源(针对多个应用程序)中管理它或在您的应用程序中使用上下文。我不会将此上下文与 业务上下文 .
混合在授权上下文中添加一个用户并添加一个角色content_contributor。在应用程序中读取该用户的权限(从中央 API、本地授权上下文、设置文件或任何最适合的内容)(基于 sub 声明).缓存它以加快性能,并应用规则来确定用户是否被允许访问该资源。
您可以使用 resource-based authorization 扩展它。将 sub 声明的值保存在内容记录中以标识所有者。当当前用户匹配 sub 声明值时,当前用户就是所有者。
您可以对团队使用相同的方法。将 teams table 添加到 业务上下文 并将用户 link 添加到一个或多个团队。直接使用 sub 声明值或间接使用用户 table,也在业务上下文中,用户被 linked 到 sub 声明价值。如果您想显示此信息(如在报告中),您可以添加姓名等。
您可以保存团队ID和/或用户ID或sub声明值( owner 是内容记录中与当前用户同属一个团队的成员)以确定允许的用户访问权限。
我的设置是这样的:
身份上下文:用户 + 用户声明。仅用于身份验证。独立于应用程序。
授权上下文:用户(id = 子声明)+ 每个应用程序:角色、权限等。在单独的 'local' 数据库或中央数据库中。仅供授权。
业务上下文:用户(Id、名称、'foreign key' 子声明,没有实际的数据库关系,因为 table 在上下文之外)+团队、个人资料、设置等。当用户 table 被省略时,链接到 sub 声明值。
为了使业务上下文中的用户 table 保持最新,请定期刷新这些值。例如,您可以在用户 x 时间后登录时更新值。或者偶尔查询身份上下文(使用 API)以请求用户信息(使用身份用户信息端点)。
在所有上下文中都可以有一个 users table,但它们都有不同的含义并包含其他信息。所以没有冗余信息。
授权发生在应用程序内部,并基于授权上下文中的业务规则(策略)和授权信息。
最后一点,当当前系统需要角色声明时(例如 User.IsInRole()
或 [Authorize("role")]
),您可以在每次调用时(从缓存中)读取角色/权限并添加这些到当前用户的声明集合(声明转换)。