firebase - 通过安全规则中的某个子值限制查询

标签 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', /* ... */);

但正如我所说,这是一个错误的假设。关于如何实现这一目标有什么建议吗?

最佳答案

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

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

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

就其本身而言,您的规则并没有错:它们只允许访问每个特定的 child ,如果它不是太老的话。他们只是不允许您再对 groupMessages/-Kb9fw20GqapLm_b8JNE 运行查询。

解决此问题的常见方法是使用一个单独的结构(通常称为“索引”),其中包含查询将返回的项目的键。在您的情况下,它看起来可能会变成每个用户加入后包含所有消息的键的索引。

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

关于firebase - 通过安全规则中的某个子值限制查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42982668/

相关文章:

java - 使用 Firebase 身份验证 UID 作为实时数据库中的子节点

javascript - 当 firebase 函数在另一个文件中时,如何让它保持打开状态

javascript - 当用户注销我的 Firebase 应用程序时,为什么它不也从身份验证提供商处注销(例如 Google)?

firebase - 如何为多页面 Web 应用程序保留 Firebase 简单登录身份验证

swift - Firebase UID 与文档 ID 和 Firestore 规则

firebase - StreamBuilder Widget 需要处理掉吗?

javascript - 从嵌套的 ng-repeat 获取 $id

Firebase 受众事件计数

java - Firebase 中的 Android Studio 值(value)增量

android - 如何用 firebase 构建友谊数据?