如何使用firebase规则检查用户组数组和记录组数组相交

时间:2015-05-11 05:17:34

标签: firebase firebase-security

我在firebase中有一个记录列表,其中包含一个包含零个或多个组的组属性。我也有firebase auth对象,它也有零个或多个组。我想为我的记录设置.read firebase规则,该规则将检查两者是否至少有两个列表中存在的组。

换句话说,我的用户有一组已分配给它的组。我有一些记录,其中还有一些组列表,用于指定用户访问它们必须具有的组。如果登录用户尝试访问记录,我想确保用户至少有一个记录所需的组。

在客户端,我会做_.intersect(userGroups, recordGroups).length > 0

之类的事情

我不确定如何在firebase规则表达式中执行此操作。如果它像这样工作会很酷。

记录:

{
  someData: "test"
  groups: ['foo', 'bar']
}

Firebase验证对象:

{
  userName: "Bob",
  groups: ['foo', 'bar']
}

规则数据:

{
  "rules": {
    "records": {
      "$recordId": {
        ".read": "data.child('groups').intersectsWith(auth.groups)"
      }
    }
  }
}

感谢。

更新 我认为如果hasChildren()使用||而不是&&我可以将组名放在关键位置并以这种方式检查它们的存在。像"data.child('groups').hasChildren(auth.groups, 'or')"

这样的东西

记录:

{
  someData: "test"
  groups: {
    'foo': '',
    'bar': ''
  }
}

UPDATE2: 根据加藤的评论&链接我意识到,即使hasChildren可以做OR,它仍然不会正常工作。如果当前用户无权访问每条记录,则对单个记录的请求将起作用,但对所有记录的请求将会出错。

目前尚不清楚如何构建数据以使其发挥作用。如果记录可能属于许多组,那该怎么办?这是一个非常常见的场景(基本上linux组权限是如何工作的)所以我不能成为唯一一个尝试这样做的人。任何人都有任何关于如何在firebase中完成此任务的想法/示例?

2 个答案:

答案 0 :(得分:0)

目前,我认为这是不可能的。这里列出了允许的有限数量的变量,方法和运算符:

Firebase Security Rules API

由于规则中不允许使用函数定义,因此您无法像在数组上调用array.some(callback)那样做任何事情来自行匹配。

我知道有三个选项:

1)复制数据,这样您就不需要进行检查。这就是我在项目中所做的:我希望在网络列表中共享网络的用户可以使用一些用户数据(名称)。最初我想检查两个成员的网络列表,看看是否至少有一个匹配。最终我意识到将每个用户的名称保存为网络数据的一部分会更容易,因此不必是用户查找需要这种奇怪的权限。我对您的数据知之甚少,无法建议您需要复制的内容。

2)使用字符串而不是数组。您可以将一个字符串转换为正则表达式(或者只是以正则表达式格式保存)并使用它来搜索其他字符串以进行匹配。Firebase DB Regex Docs

3)如果你有这样的奇怪案例,实际上运行一个以自定义方式验证请求的服务器。在数据库中,只允许对服务器的权限。您可以使用Firebase Cloud Functions或推送使用Firebase Admin SDK

的自己的服务器

答案 1 :(得分:0)

如今,还有另一种可能性:使用Firestore交付内容,可能与实时数据库同步。

在Firestore中,您可以创建如下规则:

function hasAccessTo(permissionList) {
  return get(/databases/$(database)/documents/permissions/$(request.auth.uid))
      .data.userPermissions.keys().hasAny(permissionList)
}

match /content/{itemId} {
  allow read: if hasAccessTo(resource.data.permissions.keys());
}

以下数据将允许通过$ UID读取$ CONTENTID,因为用户权限集与访问内容(使用access123所需的可能权限)相交。我的情况是,可以通过多次应用内购买来解锁内容。

{
  permissions: { 
    $UID: { userPermissions: { access123:true, access456:true } },
    ...
  },
  content: { 
    $CONTENTID: { ..., permissions: { access123, access789 } },
    ...
  }
}

对于渐进式迁移,您可以使用如下所示的单向云功能来使实时数据库和Firestore之间的数据保持同步:

exports.fsyncContent = functions.database
  .ref("/content/{itemId}")
  .onWrite((snapshot, context) => {
    const item = snapshot.after.val();
    return admin
      .firestore()
      .collection("content")
      .doc(context.params.itemId)
      .set(item);
  });