在 MongoDB 中建模访问控制

Posted

技术标签:

【中文标题】在 MongoDB 中建模访问控制【英文标题】:Modelling Access Control in MongoDB 【发布时间】:2012-11-12 23:17:53 【问题描述】:

有人有的示例吗?我想到的情况是:

有一组资源,每个资源都有自己的文档(例如汽车、人、树等)。

用户可以通过显式授权或通过成为资源所有者、存在于另一个集合(例如角色)或其他一些隐式方式来隐式地访问资源。

在一个 collection.find() 方法中,可以应用跳过和限制选项(用于分页),有没有办法检查所有这些显式和隐式路径并产生用户有权访问的资源的结果?

mysql 中,我们使用带有资源 ID、授予用户 ID、授权用户 ID 和操作(读取、写入等)的授权表对此进行了建模。然后,我们在一个查询中选择至少一个子查询为真的所有资源,然后子查询检查所有不同的访问路径,例如一项检查赠款,一项检查所有权等。

我无法在 MongoDB 中完成这项工作,我不确定这是否可能......

谢谢

【问题讨论】:

【参考方案1】:

您一次不能查询多个文档。理想情况下,访问控制不应该成为业务逻辑的一部分。您的后端 php/c#/language 应该确保当前请求已获得授权。如果是这样,那么只需查询请求的文档。

如果你觉得,你需要在 mongodb 中实现完全相同的结构,我建议你不要,那么你将需要嵌入所有这些字段(来自其他 mysql 表的那些可以帮助你识别请求被授权)在每个集合的每个文件中。您将复制数据(对其进行非规范化)。这带来了确保所有副本都已更新并具有相同值的问题。

编辑 1:

让我们谈谈 Car 文档。要跟踪其所有者,您将拥有 owner 属性(这将包含所有者文档的 _id)。要跟踪所有可以“使用”(显式授予)汽车的用户,您将拥有一个数组 allowerdDrivers(这将包含每个 user 文档的 _id)。让我们假设发出请求的当前用户属于“管理员”角色。 user 文档将有一个数组applicableRoles 存储每个适用角色文档的_id

要检索用户有权访问的所有汽车,您只需进行两次查询。一个来取他的角色。如果他是管理员,则归还所有汽车。如果他不是,则进行另一个查询,其中owner 等于他的id or allowedDrivers 包含他的id。

我了解您的实际用例可能更复杂,但可能有一种面向文档的方法可以解决这个问题。您必须意识到,在文档中建模数据的方式与在 RDbMS 中建模的方式大不相同。

【讨论】:

我认为可能是这种情况。在业务逻辑中这样做会非常缓慢且效率低下。在搜索或列出这些资源的情况下,您必须全部或一个接一个地阅读它们,并将所述业务逻辑应用于它们,如果它们失败则将它们丢弃并继续阅读,直到达到您的分页限制。它要复杂得多,但值得在查询时在数据层执行此操作。如果没有事务,复制似乎很危险,因为您希望全部更新或不更新。也许 MongoDB 不适合我们的用例。 更新了我的答案。只是一个建议,你可能想在 mongodb google 用户组上问这个问题。我相信文档数据库在大多数应用程序中都可以发挥同样的作用,如果不是更好的话。而且您的应用可能不是规则的例外。 接受这个作为答案 - 对我来说关键是可以执行超过 1 个查询:)【参考方案2】:

在业务逻辑中这样做会非常缓慢和低效。

怎么会?这是业务逻辑,如果用户 a 拥有帖子 b,则让他们执行操作(MVC 风格),否则不要。

对我来说这听起来像是业务逻辑,大多数框架都认为这个业务逻辑被放置在控制器动作中(MVC 范式);即在 PHP Yii 中:

Yii::app()->roles->hasAccess('some_view_action_for_a_post', $post)

我认为通过在数据库端执行此操作,您将存储层与业务层混淆了。

此外,由于某些基于角色的权限操作可以让您提交的查询变得非常复杂,因此必须有很多子选择。考虑到 MySQL 如何创建和处理结果集(子选择不是 JOINS),我感觉这些查询的扩展性不是特别好。

您还必须考虑何时要更改角色或定义角色的函数,该函数可以访问某个对象,您必须直接更改 SQL 查询,而不是仅仅将角色添加到角色表和为该角色分配对象属性并为该角色分配用户(AKA 代码更改)。

因此,我会认真研究其他语言(以及您自己的)的其他框架如何执行 RBAC,因为我认为您已经模糊了界限,并且您所做的事情让您的生活变得非常艰难,实际上这里可能是一个不错的选择起点:Group/rule-based authorization approach in node.js and express.js

【讨论】:

确定用户是否有权访问特定对象不是问题,而是查询用户有权访问的对象列表。如果数据库中有数千个项目,并且您想查询用户有权访问的项目,那么逐个检查并调用 hasAccess 会非常慢。 @stevex 那么您是 dong RBAC 错误,相反,您应该拥有 edit-posts 权限,然后在代码中检测他们是否可以编辑该帖子,权限仅用于访问操作而不是对象 @stevex 我应该澄清 RBAC 和优化业务逻辑以决定用户是否拥有对象的所有权是两件不同的事情,自从这篇文章以来已经有很多年了,OP 似乎已经澄清了我回答后他们在上述答案中的观点

以上是关于在 MongoDB 中建模访问控制的主要内容,如果未能解决你的问题,请参考以下文章

mongodb的访问控制

MongoDB 访问权限控制

MongoDB 启用访问控制

从 Google Cloud Functions 控制台中访问 MongoDB Atlas 集群

MongoDB 3.0+安全权限访问控制

MongoDB 3.0+安全权限访问控制