【问题标题】:How to allow user to query collection but only access certain results in collection?如何允许用户查询集合但只访问集合中的某些结果?
【发布时间】:2016-05-10 10:06:37
【问题描述】:

第一次在 firebase 工作并设置复杂的(对我而言)规则。

我有一组具有“parentId”属性的子项。我只希望某些角色和用户阅读此表。具体来说,我希望任何教练或裁判角色都能够像任何孩子的父母一样阅读。

我认为问题出在集合级别 .read 的“data.child('parentId').val() === auth.uid”。我觉得我完全遵循了这里的示例,但它仍然无法正常工作:https://www.firebase.com/docs/security/api/rule/data.html

谁能指出我在安全规则中做错了什么?

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

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

"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);
                    }
                })

        })
    }

cmets 应该解释我的目的。问题是用户无法通过父母 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').equalTo(parentId) 的语法,并且 Chrome 开发工具网络在我触发此命令时未显示任何活动...

【问题讨论】:

    标签: firebase firebase-security


    【解决方案1】:

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

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

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

    如果不了解规则是自动评估的,则似乎获取 /records/ 路径会返回 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/ 路径,但请注意,rec1 的规则从未评估过,因为它不在我们请求的路径中。要获取 rec1,我们需要直接访问它:

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

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

    关于相同的一些问题:

    【讨论】:

    • 感谢弗兰克的详细回复。在上面的示例中,如果查询只是专门查找符合安全规则的记录怎么办?要修改您的示例: { "rules": { "records": { ".read": "data.child('read').val() === true" } } } } 和这样的查询:ref .child('records').orderByChild('read').equalTo(true) 这相当于我正在做的事情。正如我的问题所述,我不认为我正在使用安全规则进行过滤。
    猜你喜欢
    • 1970-01-01
    • 2021-12-25
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    • 2019-02-05
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    相关资源
    最近更新 更多