比较 Firestore 规则中的文档时间戳

jor*_*aff 5 firebase-security google-cloud-firestore

我在编写和测试 Firestore 规则时遇到了一个奇怪的问题。这就是我想要实现的目标:

  • 当应用程序启动时,用户会匿名登录。用户开始新游戏。
  • 我创建了一个基本上仅包含时间戳的“会话”。
  • 玩家玩游戏,获得一定的高分,然后转到可以将分数发送到全局高分列表的屏幕。提交高分后,我会检查该玩家是否存在现有会话,以及已经过去的时间是否足够长以使高分被视为有效。

在客户端(javascript)上,我使用以下行发送文档中的时间戳:

firebase.firestore.FieldValue.serverTimestamp()
Run Code Online (Sandbox Code Playgroud)

这是当前的规则集。可以看到,只有当新的higscore的createdAt晚于session的createdAt时,才能创建分数。

service cloud.firestore {
    match /databases/{database}/documents {
        function isValidNewScoreEntry() {
            return request.resource.data.keys().hasOnly(['createdAt', 'name', 'score']) &&
            request.resource.data.createdAt is timestamp &&
            request.resource.data.name is string &&
            request.resource.data.score is int &&
            request.resource.data.name.size() <= 20
        }

        match /highscores/{entry} {
            allow list: if request.query.limit <= 10;
            allow get: if true; 
            allow create: if isValidNewScoreEntry() &&
      request.resource.data.createdAt > get(/databases/$(database)/documents/sessions/$(request.auth.uid)).data.createdAt;
        }

        function isValidNewSession() {
            return request.resource.data.keys().hasOnly(['createdAt']) &&
            request.resource.data.createdAt is timestamp
        }

        match /sessions/{entry} {
            allow list: if false;
            allow get: if false; 
            allow create: if isValidNewSession();
            allow update: if isValidNewSession();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我模拟/测试这些规则时,我收到一条错误,指出我无法将“时间戳”与“地图”进行比较。我不知道为什么“createdAt”值是一个地图,但似乎 get() 方法返回的内容与预期不同。

我的问题是:将新提交的条目中的属性createdAt与现有会话文档的属性createdAt进行比较的正确方法是什么,就像我在上述规则中尝试做的那样。

这就是“分数”条目的样子 这是“会话”条目的样子

编辑:

我做了更多挖掘,发现这条线有效:

if request.resource.data.createdAt.toMillis() > get(/databases/$(database)/documents/sessions/$(request.auth.uid)).data.createdAt.seconds * 1000;

这非常清楚地表明,两个createdAt 的格式并不相同。最后一个似乎是具有“秒”和“纳秒”属性的基本对象。我确信它源于 Timestamp 接口,但它会作为平面对象返回,因为此处找到的方法都不存在,并且在尝试调用它们时会给出错误。然而,属性“秒”确实存在于第二个时间戳上,但在第一个时间戳上无法访问。

jor*_*aff 1

我发现了为什么时间戳不是我所期望的,并被转换为“地图”。在深入研究文档后,我发现该get()方法返回一个resource. resource有一个属性data:地图。因此,该get()方法不会像我预期的那样返回文档,而是返回一个平面 JSON 对象,该对象为我提供在数据库中找到的所有属性。

https://firebase.google.com/docs/reference/rules/rules.firestore

https://firebase.google.com/docs/reference/rules/rules.firestore.Resource

  • 那么,您做了什么来改变规则以使它们发挥作用? (2认同)