限制安全规则中某个子值的查询

时间:2017-03-23 17:11:10

标签: firebase firebase-realtime-database firebase-security

我正在努力想出构建我的数据库及其相关安全规则的最佳方法。

我有聊天组,用户可以随时添加到这些组中。将用户添加到组后,他们应该只能检索之后发送的消息。它们不应该能够检索在它们(用户)被添加到组之前发送的任何消息。

我的第一种方法错误地认为安全规则仅适用于被查询的数据。

为这个问题简化它,我有以下结构:

{
    "groups": {
        "-Kb9fw20GqapLm_b8JNE": {
            "name": "Cool people"
        }
    },
    "groupUsers": {
        "-Kb9fw20GqapLm_b8JNE": {
            "3JzxHLv4b6TcUBvFL64Tyt8dTXJ2": {
                "timeAdded": 1230779183745
            },
            "S2GMKFPOhVhzZL7q4xAVFIHTmRC3": {
                "timeAdded": 1480113719485
            }
        }
    },
    "groupMessages": {
        "-Kb9fw20GqapLm_b8JNE": {
            "-KbKWHv4J4XN22aLMzVa": {
                "from": "3JzxHLv4b6TcUBvFL64Tyt8dTXJ2",
                "text": "Hello",
                "timeSent": "1358491277463"
            },
            "-KfHxtwef6_S9C5huGLI": {
                "from": "S2GMKFPOhVhzZL7q4xAVFIHTmRC3",
                "text": "Goodbye",
                "timeSent": "1493948817230"
            }
        }
    }
}

这些安全规则:

{
    "rules": {
        "groupMessages": {
            ".indexOn": "timeSent",
            "$groupKey": {
                ".read": "root.child('groupUsers').child(auth.uid).child($groupKey).child('timeAdded').val() <= data.child('timeSent').val()"
                ".write": "!data.exists() && root.child('groupUsers').child(auth.uid).child($groupKey).exists() && newData.child('from').val() === auth.uid",
            }
        }
    }
}

有了这个,我想我可以像这样检索特定群组的消息:

var myTimeAdded = /* already retrieved from the database */;
firebase.database()
  .ref('groupMessages/-Kb9fw20GqapLm_b8JNE')
  .orderByChild('timeSent')
  .startAt(myTimeAdded)
  .on('child_added', /* ... */);

但就像我说的那样,这是一个错误的假设。关于如何实现这一目标的任何建议?

1 个答案:

答案 0 :(得分:2)

在附加侦听器的位置强制执行读取规则。

所以在你的情况下是groupMessages/-Kb9fw20GqapLm_b8JNE。如果您的用户具有读取权限,则允许侦听器。如果用户没有读取权限,则拒绝/取消侦听器。

这意味着规则不能用于过滤数据。我们经常将此称为“规则不是过滤器”,这是对Firebase安全模型不熟悉的开发人员最常见的陷阱之一。参见:

你自己的规则没有错:他们只允许访问每个特定的孩子,如果它不是太老了。他们不允许您再次在groupMessages/-Kb9fw20GqapLm_b8JNE上运行查询。

解决此问题的常见方法是使用项目的键来建立单独的结构(通常称为“索引”),否则您的查询将返回该结构。在您的情况下,看起来这可能会成为每个用户的索引,并在他们加入后使用所有消息的键。

但我会说实话,这听起来像是在尝试以SQL方式使用安全规则。用户似乎不太可能允许查看较旧的消息。更有可能的是,您不希望用户对旧消息感到烦恼。在这种情况下,我只是用查询解决它(就像你已经拥有的那样)并删除".read"规则。

相关问题