我有一个“关系”模型,具有以下类型:
用户可以属于多个组,并且组可以具有多个用户。
项目具有允许其读取或执行操作的用户和组。
最常见的查询是,用户通过其ID查询项目。为此,必须检查用户是否具有查询项目所需的权限。换句话说,它或其一个组必须对该项目具有权限。
到目前为止我想出了什么
一种解决方案是,这些商品具有以下属性:
用户
项目:
'data'
:此项的数据<user/group-id>
:对此用户或组的权限因此要检查权限,必须要
问题
我觉得这可能会导致大量查询,尤其是在组数很高的情况下。
是否有一种无需昂贵的权限检查即可实现此权限模型(或类似权限模型)的方法?
答案 0 :(得分:0)
简短答案-将权限与数据分开。
详细答案-您应该使用轻量级权限表来存储组与用户和项目之间的关系。您不应该在项目上使用任何与权限相关的排序键,并且除非有特殊原因允许使用具有相同ID的项目(例如存储项目的版本历史记录),否则您可能根本不应该使用任何排序键为您的物品。
权限表具有两个属性,我将其称为entity
(哈希键)和relationship
(排序键)。 (不过,您可以使用所需的任何名称。)该表还具有GSI,其中relationship
是哈希键,而entity
是排序键。因为此表的行很小,所以查询非常便宜。您可能读取超过100行,并且仅消耗1个RCU。
entity
属性只是一个userId或groupId。 relationship
属性是关系类型和另一个ID的组合。 (您可以将任何所需的ID用于ID,但我将在所有示例中使用数字。)
以下是一些示例数据:
entity | relationship
===========================================
user-0001 | member-of:group-1000
user-0001 | member-of:group-3000
user-0002 | can-access:item-1111
user-0002 | member-of:group-2000
group-1000 | can-access:item-1111
group-2000 | can-access:item-2222
要确定用户是否有权访问给定项目,您需要两个查询。在权限表中查询userId,并在GSI中查询“可以访问” itemId关系。然后,比较两个查询结果以查看是否有共同的组(或者用户是否有权直接访问该项目)。
例如,如果您想查看user-0001
是否可以访问item-1111
,则可以查询user-0001
并返回[member-of:group-1000, member-of:group-3000]
。然后,您将在GSI中查询can-access:item-1111
,然后返回[user-0002, group-1000]
。比较这两个结果,您会发现user-0001
可以通过item-1111
来访问group-1000
。
此模型的另一个好处是它足够灵活,可以处理其他权限用例。以下是该数据的外观示例:
entity | relationship
===========================================
user-0001 | admin-of:group-1000
user-0001 | member-of:group-1000
user-0002 | member-of:group-2000
user-0002 | owner-of:item-1111
group-1000 | can-write:item-1111
group-1000 | can-read:item-1111
group-2000 | can-read:item-1111
在此示例中,我们还有一些用户可以管理组,我们已经分离了项目的读写权限,并且可以将用户或组定义为项目的所有者(这可能意味着他们可以修改谁有权读取或写入该项目。
一个警告是,这假定组不能嵌套。如果可以嵌套组,那么您将需要更多查询来遍历嵌套组的层次结构,使用AWS Neptune或其他数据库来存储权限可能会更好。