如何允许用户查询集合但只能访问集合中的某些结果?

时间:2016-02-01 20:02:52

标签: firebase firebase-security

第一次使用firebase并设置复杂(对我而来)规则。

我有一个孩子的集合,有一个属性" parentId"。我只希望某些角色和用户阅读此表。具体来说,我希望任何教练或裁判角色能够阅读以及任何孩子的父母。

我认为问题出在" data.child(' parentId')。val()=== auth.uid"在收集级别.read。我觉得我完全按照这里的例子,但它仍然没有工作:https://www.firebase.com/docs/security/api/rule/data.html

有人能指出我在安全规则中做错了吗?

我知道安全规则不会过滤,我不相信这是特定问题的一个例子,因为我的查询特意将结果限制为我试图通过安全规则允许的内容(尽管我可能弄错了) )。

这是当前的安全规则。评论应该解释我的目标:

"children": {
      // give ability of any coach or referee to read any child. Give refs ability to write to any child. Allow parent to query for their own children.
      ".read": "(data.child('parentId').val() === auth.uid) ||(root.child('users').child(auth.uid).child('role').val() === 'coach') || (root.child('users').child(auth.uid).child('role').val() === 'referee')",
      ".write": "root.child('users').child(auth.uid).child('role').val() === 'referee'",
      ".indexOn": ["parentId", "isApproved"],
      "$child": {
        // give a parent read and write access to only their specific children.
        ".read": "root.child('children').child($child).child('parentId').val() === auth.uid",
        ".write": "root.child('children').child($child).child('parentId').val() === auth.uid"
      }
 }

在我的代码中,我正在通过parentId查询所有子项。这是我的javascript失败,错误:permission_denied:客户没有权限访问所需的数据。":

factory.getChildrenByParent = function(parentId){
        return new Promise(function(resolve, reject){
            childrenRef.orderByChild('parentId').equalTo(parentId)
                .once('value', function(childrenResponse){
                    var children = childrenResponse.val();
                    processChildren(children);
                    resolve(children);
                },
                function(err){
                    if(err){
                        reject(err);
                    }
                })

        })
    }

评论应该解释我的目标。问题是用户无法通过父ID(等于auth.uid)查询子项。 他们可以通过以下方式查询一个:

factory.getChildById = function(id){
        return new Promise(function(resolve, reject){
            childrenRef.orderByKey().equalTo(id)
                .once('value', function(childResult){
                    var childObjects = childResult.val();

                    processChildren(childObjects);
                    var child = Utilities.getFirst(childObjects);
                    resolve(child);

                },
                function(err){
                    if(err){
                        reject(err);
                    }
                })
        })
    }

我尝试过使用模拟器,但我无法弄清楚.orderByChild(' parentId')的等级语法.aquantTo(parentId)和Chrome开发工具网络没有'当我开火时显示任何活动...

1 个答案:

答案 0 :(得分:7)

您可能希望再次阅读Firebase documentation on "Rules are not filters"部分。

  

规则以原子方式应用。这意味着如果在该位置或授予访问权限的父位置没有规则,则读取或写入操作会立即失败。即使每个子路径都可访问,在父位置读取也会完全失败。考虑这个结构:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}
  

如果不理解规则是以原子方式进行评估的,那么获取/ records / path似乎会返回rec1而不是rec2。但实际结果是错误:

ref.child("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
  

由于/ records /的读取操作是原子的,并且没有读取规则允许访问/ records /下的所有数据,因此会抛出PERMISSION_DENIED错误。如果我们在App Dashboard中的安全模拟器中评估此规则,我们可以看到读取操作被拒绝:

Attempt to read /records with auth=Success(null)
/
/records
No .read rule allowed the operation.
Read was denied.
  

操作被拒绝,因为没有读取规则允许访问/ records / path,但请注意,rec1的规则从未被评估过,因为它不在我们请求的路径中。要获取rec1,我们需要直接访问它:

ref.child("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});

换句话说:只有当您拥有该位置的读取权限时才能对某个位置执行查询

有关同样的问题: