基于角色的权限
在此页面上
Overview
您可以定义自动分配给传入用户请求和“设备同步”会话的角色,从而保护应用程序的数据。每个角色都具有细粒度的数据访问权限和决定角色何时应用的动态条件。
有关如何使用 Device Sync 为常见场景配置权限的示例,请参阅 Device Sync 权限指南。
什么是权限?
权限是 Atlas App Services 分配给各个用户的一种状态,用于控制他们可以或不可以对应用程序的数据执行哪些操作。App Services 同时使用文档级和字段级权限:
文档级权限
角色的文档级权限决定了其可以执行哪些影响整个文档的操作。这些权限始终适用于整个文档,无论内容如何。角色可以具有以下文档级权限:
插入:您可以插入新文档。
删除:可以删除现有文档。
搜索:您可以使用 Atlas Search 搜索文档。
字段级权限
角色的字段级权限决定了用户是否可以读取或写入文档中的字段。这些权限仅影响其应用的字段,因此用户只能对整个文档的子集有读取或写入权限。
您可以为特定字段定义字段级权限,并为未显式定义的任何其他字段定义默认读取/写入权限。
读取权限流程图
下图显示了 App Services 如何确定用户是否可以读取给定文档:
写权限流程图
下图显示了 App Services 如何确定用户是否可以写入给定文档:
角色
角色是用户对 MongoDB 集合中文档可能拥有的一组命名权限。角色具有“应用时间”表达式,用于确定 App Services 是否应将该角色分配给用户。角色还具有一组文档级和字段级权限,用户在分配该角色时拥有这些权限。
App Services 仅会提交用户根据其所分配角色有权执行的操作。如果某一角色无权读取文档或其某些字段,App Services 会在结果中忽略该文档或此类字段。
例子
考虑一个名为 employees
的集合,其中每位员工都有自己的文档,文档包含所有就业数据。该集合可能有两个角色:员工和经理。我们不使用 Device Sync,因此 App Services 基于每个文档选择角色。
如果用户请求自己的文档,则他们的角色是“员工”。员工可以读取和写入自己的数据,但不能创建或删除自己的文档。
如果用户请求其姓名列在用户的
manages
数组中的人员的文档,则他们的角色是“经理”。经理可以读取和写入直接下属的数据,也可以创建和删除他们的文档。如果用户既不是给定文档的 Employee 也不是 Manager,则他们没有角色并且无法读取、写入或搜索该文档。
{ "name": "Manager", "apply_when": { "email": "%%user.custom_data.manages" }, "insert": true, "delete": true, "read": true, "write": true, "search": true, "fields": {}, "additional_fields": { "read": true, "write": true } } { "name": "Employee", "apply_when": { "email": "%%user.data.email" }, "insert": false, "delete": false, "read": true, "write": true, "search": true, "fields": {}, "additional_fields": { "read": true, "write": true } }
{ "_id": ObjectId(...), "employeeId": "0528", "name": "Phylis Lapin", "team": "sales", "email": "phylis.lapin@dundermifflin.com", "manages": [] } { "_id": ObjectId(...), "employeeId": "0713", "name": "Stanley Hudson", "team": "sales", "email": "stanley.hudson@dundermifflin.com", "manages": [] } { "_id": ObjectId(...), "employeeId": "0865", "name": "Andy Bernard", "team": "sales", "email": "andy.bernard@dundermifflin.com", "manages": [ "phylis.lapin@dundermifflin.com", "stanley.hudson@dundermifflin.com" ] }
App Services 如何分配角色
App Services 会在不同时间分配角色,具体取决于您是否使用了 Device Sync (Flexible Mode)(Device Sync(灵活模式))。
使用 Device Sync 时,App Services 会在同步会话开始时为每个要同步的集合分配角色。同步会话是打开和关闭同步连接之间的时间段。
不使用 Device Sync 时,App Services 会按每个文档、每个请求分配角色。
无论是否使用 Device Sync,您都可以定义一组特定于集合的角色以及适用于任何其他未指定集合的默认角色。要分配角色,App Services 会按照您指定的顺序评估每个角色的“apply when”表达式。“apply when”表达式计算结果为 true 的第一个角色将成为分配的角色。如果没有角色匹配,则访问被拒。
给定请求或同步会话的评估角色集取决于用户正在访问的集合。如果为集合定义了任何集合级角色,则会评估集合级角色。否则,将评估数据源的默认角色(如有)。
如果没有集合级角色适用,App Services 不会“回退”到默认角色。如果定义了任何集合级角色,则仅评估集合级角色。当且仅当未定义集合级角色时,才会评估默认角色。
无 Device Sync
不使用 Device Sync 时,App Services 会动态为每个文档分配角色。对于与传入查询匹配的每个文档,用户会被分配一个单独的角色,或者不分配任何角色。
首先,应用程序会计算和应用筛选器,然后运行查询。
例子
使用以下请求,App Services 将评估 restaurants
集合中 city
字段设置为 "Chicago"
的每个文档的角色:
db.restaurants.updateMany( { "city": "Chicago" }, { "$set": { "city": "Chicago, IL" } } );
对于查询返回的每个文档,您的应用会按角色顺序评估可能的角色,并分配第一个适用的角色(如有)。如果针对给定文档运行时“apply when”表达式的计算结果为true
,则将角色应用于给定文档。
例子
员工将始终在自己的团队中,因此员工和队友角色都适用于他们自己的文档。但是,他们只能使用一种角色,因此我们希望使用员工,因为它更具体。
要配置此功能,请在集合的角色定义中指定员工早于团队成员:
{ "database": "<Database Name>", "collection": "<Collection Name>", "roles": [ { "name": "Manager", ... }, { "name": "Employee", ... }, { "name": "Teammate", ... } ] }
有 Device Sync
使用 Device Sync 时,App Services 会在每个灵活同步会话开始时为每个同步的集合分配角色。该角色决定了在会话期间要为每个集合应用哪些权限。
App Services 最多为每个集合分配一个角色。如果没有为给定的同步集合指定角色,App Services 将使用默认角色。如果没有角色适用于一个集合,则用户无法同步(或读取或写入)该集合中的任何条目。
角色在会话期间保持分配状态。如果与用户会话角色相关的某些内容在用户会话期间发生变化,则在用户启动新会话之前不会为其分配更新角色。例如,如果用户的元数据或角色的“应用时间”表达式发生变化,则用户会继续使用该集合的现有角色,直到下次启动会话为止。
使用 Device Sync 时,权限系统方面有一些特殊注意事项。请参阅与 Device Sync 兼容的权限。
有关使用常见权限模型设置灵活同步的指南,请参阅 Device Sync 权限指南。
Apply When 表达式
角色的“apply when”表达式是确定是否应分配角色的规则表达式。
您可以使用表达式变量来实现角色动态化。例如,您可以使用 %%user
扩展来指代发出请求的特定用户。此举可让您根据每个用户来自定义数据访问权限。
不使用 Device Sync 时,您可以参考正在为其分配角色的当前文档。例如,您可以使用 %%root
。这使您可以基于每个文档自定义数据访问权限。
文档筛选器
角色的 document_filters
表达式决定了是否可以评估角色的后续文档级和字段级权限。这是“设备同步”所必需的。
注意:App Services 按每个文档来评估文档筛选器。不要将它们视作顶级查询筛选器。
角色顺序
给定集合的每个角色均有一个位置,它决定了对这些角色进行计算和应用的顺序。按角色顺序计算表达式时,每个角色均会进行应用,直到某一角色适用或没有更多角色为止。
在给定查询中,某一用户对于每个文档只能拥有一个角色。当多个角色的“apply when”表达式为 true 时,角色顺序决定了哪个角色适用。因此,在定义角色时,请将最具体的角色放在前面。
同步兼容性
如果启用 Device Sync(灵活模式),则分配的角色必须是同步兼容的。有关详细信息,请参阅同步兼容的角色。
定义角色和权限
您可以通过 App Services 用户界面或使用 App Services CLI 部署配置文件来配置应用的数据访问规则:
单击左侧导航菜单中的 Rules ,然后从数据源的集合列表中选择一个集合。您也可以选择Default roles and filters ,为整个集群配置默认规则。
如果尚未定义角色,系统将提示您创建新的角色。否则,您将看到现有角色的有序列表。
单击 Add role 以定义新角色。您可以使用预设角色作为起点,或者单击 Skip (start from scratch)。
为角色命名。该名称可以是您想要的任何名称,但在给定集合中必须是唯一的。可以考虑使用描述用户和/或其与数据的关系的名称。例如,
Admin
或Owner
。定义一个“apply when”表达式,用于确定给定用户对给定文档何时具有该角色。
为角色定义文档级权限。
为角色定义文档过滤器。这是 Device Sync(灵活模式)所必需的。
使用下拉列表为角色选择字段级权限。如果选择 Specify field-level permissions,请输入要为其定义权限的字段名称。
对于您命名的每个字段和 Additional Fields,通过选择 None、Read 或 Read & Write 来指定权限。
保存角色。
如果为一个集合分配了多个角色,您可以通过单击每个角色上的箭头来修改角色顺序。
拉取应用程序的最新版本。
appservices pull --remote="<Your App ID>" 为一个或多个集合定义角色和筛选器。您还可以定义适用于任何未配置集合的默认角色和筛选器。详见规则配置。
/data_sources/<data source>/<database>/<collection>/rules.json{ "database": "<Database Name>", "collection": "<Collection Name>", "roles": [ { "name": "<Role Name>", "apply_when": {}, "document_filters": { "read": { <Expression> }, "write": { <Expression> } }, "insert": true, "delete": true, "search": true, "fields": { "myField": { "read": true, "write": true } }, "additional_fields": { "read": true, "write": true } } ], "filters": [ { "name": "<Filter Name>", "apply_when": {}, "query": {}, "projection": {} } ] } /data_sources/<data source>/default_rule.json{ "roles": [ { "name": "<Role Name>", "apply_when": {}, "document_filters": { "read": { <Expression> }, "write": { <Expression> } }, "insert": true, "delete": true, "search": true, "fields": { "myField": { "read": true, "write": true } }, "additional_fields": { "read": true, "write": true } } ], "filters": [ { "name": "<Filter Name>", "apply_when": {}, "query": {}, "projection": {} } ] } 部署您的应用。
appservices push
注意
App Services 基于角色的权限的安全注意事项
虽然基于角色的权限和过滤器可以隐藏集合中的特定文档和字段,但如果系统允许任意查询访问该集合,则可能会泄露数据。
例如,根据集合中存储的值引发错误(例如被零除错误)的查询或函数可能会泄露有关文档的信息,即使角色或过滤器禁止查询用户直接查看文档也是如此。用户还可以通过其他方法对基础数据进行推断(例如,测量查询执行时间,这可能会受到数据分布情况的影响)。
请注意这种可能性,并在必要时对数据访问模式进行审核。