【问题标题】:Restrict querying by a certain child value in security rules通过安全规则中的某个子值限制查询
【发布时间】:2017-08-16 09:33:35
【问题描述】:

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

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

我的第一种方法错误地假设安全规则只适用于被查询的数据。

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

{
    "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', /* ... */);

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    就其本身而言,您的规则并没有错:它们只允许访问每个特定的孩子,前提是孩子不太老。他们只是不再允许您在 groupMessages/-Kb9fw20GqapLm_b8JNE 上运行查询。

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

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

    【讨论】:

    • 是的,我在阅读文档后认为是这样。经过一番谷歌搜索后,我似乎找不到任何替代方法,所以我想我应该问一下。有什么建议?您能否指出我可以阅读的任何资源以提供一些启示?谢谢你的回答:)
    • 是的,我分心了。现在添加更多信息。
    • 感谢编辑!我之前考虑过“索引”,但我试图避免这样做,尽管它似乎是最好的解决方案。我可以让每条新消息触发一个函数,该函数将消息键复制到当前组中每个用户的单独结构中。我对这种方法的主要担忧是,快速连续发送的消息可能会暂时出现乱序,因为函数并不总是按照它们被触发的顺序运行。我希望不限制可以根据日期检索哪些消息是一个选项,但它不在这个特定的应用程序中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-17
    • 2021-03-25
    • 2021-07-31
    • 2012-12-27
    相关资源
    最近更新 更多