firestore安全规则获取动态密钥的价值?

时间:2020-03-21 17:01:15

标签: google-cloud-firestore firebase-security

文档结构:

{
    [id 1] {
        field1: "value",
        field2: "value",
        field3: "value"
    }
    [id 2] {
        field1: "value",
        field2: "value",
        field3: "value"
    }
    [id 3] {
        field1: "value",
        field2: "value",
        field3: "value"
    }
}

地图ID参考文档,不能进行硬编码,但是每个地图中的字段名称(field1,field2 ...)都是相同的

有没有一种方法可以检查任何1个映射中只有1个字段被更改,并在满足这些条件的情况下允许写操作?

2 个答案:

答案 0 :(得分:1)

安全规则不够灵活,无法满足您的要求。这需要循环和赋值,而这两种语言都不可用。我建议改为使用后端从客户端收集数据,然后检查其是否有效。

答案 1 :(得分:1)

为了将所有验证逻辑保留在Firestore中,您可以使用的一个技巧是为写入请求增加冗余。例如,您可以从客户端发送以下数据:

firestore.collection('A').doc('B').update({ 
  'your_id_here': { 
    field1: 'my new value',

    // keep old data, since we are updating a nested object
    field2: 'original value', 
    field3: 'original value'
  },
  
  // this is the redundancy component
  meta: { id: 'your_id_here' }
});

然后,在您的Firestore规则中,可以如下定义写入规则:

function valid() {

  // grab ID from "redundant" part of the request
  let metaID = request.resource.data.meta.id;

  // grab changed keys in the root of the document
  let rootAftectedKeys = request.resource.data.diff(resource.data).affectedKeys(); 

  // validate root keys; need to include "meta", since it is now also part of the object
  let rootChangesGood = rootAffectedKeys.hasOnly([metaID, 'meta']);
  
  // grab the nested object in question             
  let nestedObjectChanges = request.resource.data[metaID].diff(resource.data[metaID]).affectedKeys();

  // check there was only one affected key
  let nestedObjectChangesGood = nestedObjectChanges.size() == 1;

  return rootChangesGood && nestedObjectChangesGood;
}
allow write: if valid();

如您所见,我正在使用metaID变量来动态访问对象的键。

此方法的优点是(1)所有验证逻辑都在Firebase中,并且(2)比执行云功能要快得多(因为您仅直接与Firestore通信)。

这种方法的缺点是,您将拥有这个meta对象,每个人都可以看到。最重要的是,我将添加更多验证,以确保meta对象本身仅具有正确格式的必需数据。我强烈建议彻底测试所有可能的情况。