Firestore 安全规则 - 更新数组字段 - 只允许推送 (arrayUnion)

问题描述 投票:0回答:3

是否可以只允许推入数组字段(在文档中),但阻止写入该数组中的任何现有值?

myDocument: {
    myArray: [
        "value1",
        "value2"
    ]
}

我想在

"value3"
中添加
myArray
。我打算使用 firestore 文档

中提出的这种方法

但我想阻止除上述之外的

myArray
字段的任何其他更新,并且我没有找到一种优雅的方法来使用云 Firestore 安全规则来执行此操作。

是否有办法接受

myArray
字段的更新(如果使用
arrayUnion
进行更新)并阻止所有其他更新请求?

firebase google-cloud-firestore firebase-security
3个回答
6
投票

因为永远不会太晚!

这是我的解决方案!为了仅允许使用 arrayUnion 更新字段,我使用了两件事:

  • .size()
    检查用户是否正在更新数组仅添加一个元素,因此我检查新数组的大小是否等于旧数组的大小 + 1 👌

request.resource.data.offers.size() == resource.data.offers.size() + 1

  • .hasAll
    确保用户仅添加新值而不编辑现有值(非常重要的一点⚠️)

request.resource.data.offers.hasAll(resource.data.offers)

提供的最终版本是我的数组,他们只接受

arrayUnion 
作为更新👇

match /swaps/{swapId} {
      allow create: if request.auth != null;
      allow read: if request.auth != null;
      allow update: if (
          request.resource.data.offers.size() == resource.data.offers.size() + 1
          && request.resource.data.offers.hasAll(resource.data.offers)
      );
      allow delete: if false;
}

0
投票

这是最全面的解决方案,可以确保以下几点:

  • 只添加了一项

  • 该项目已添加到数组的末尾

  • 现有数组项尚未更改或重新排列

    match /winners/{gameId} {
    
      // Not really important stuff:
      allow create: if false; // I'm creating documents with a cloud function, don't want users to create them with random data.
      allow delete: if false;
      allow read: if request.auth != null;
    
      // THE IMPORTANT STUFF:
      allow update: if 
        request.auth != null // Not really important to the question, but I always make sure users are authenticated.
        &&
        (
          request.resource.data.winners.size() == resource.data.winners.size() + 1 // Ensure only one item was added.
          && 
          resource.data.winners == request.resource.data.winners[0:resource.data.winners.size()] // This is the most important part - make sure the original array is contained in the first part of the new array. See notes below for more info how it works.
        );
    }
    

关键是从新列表创建一个子列表并将其与原始列表进行比较(数组在安全规则中称为列表)。子列表需要与原始列表的长度相同,因此我们使用 range 运算符

[i:j]
从新列表创建子列表,从索引
0
开始,与原始列表具有相同的长度。请注意,文档当前是错误的,称范围运算符需要两个索引。根据我的测试,它确实需要一个起始索引和许多元素来包含。


0
投票

这是我基于@Trev14 答案的解决方案。

let stored = resource.data.myArray;
let incoming = request.resource.data.myArray;

return incoming is list 
    && incoming.size() == stored.size() + 1
    && (stored.size() == 0 || incoming[0:stored.size()] == stored)

stored.size() == 0
时允许更新对我来说很重要,因为列表可能为空。由于某种原因,
incoming[0:0]
不能等于
stored

© www.soinside.com 2019 - 2024. All rights reserved.