Firebase Firestore安全规则-如何防止修改特定字段

Firebase Firestore安全规则-如何防止修改特定字段,firebase,google-cloud-firestore,firebase-security,Firebase,Google Cloud Firestore,Firebase Security,假设我们有一个名为todo的Firestore集合,其中每个todo看起来如下: { name: "Buy milk", completed: false, user: "eYtGDHdfgSERewfqwEFfweE" // some user's uid } allow update: if request.auth.uid == resource.data.user //&& !request.writeFields.h

假设我们有一个名为
todo
的Firestore集合,其中每个todo看起来如下:

{
    name: "Buy milk",
    completed: false,
    user: "eYtGDHdfgSERewfqwEFfweE" // some user's uid
}
allow update: if request.auth.uid == resource.data.user
              //&& !request.writeFields.hasAny(["user"]);
              //&& !(request.writeFields.hasAny(["user"]));
              //&& !request.resource.data.keys().hasAny(["user"]);
              //&& !('user' in request.resource.data);
              //&& ('user' in request.resource.data) == false;
              //&& !('user' in request.writeFields);
现在,我想防止在更新过程中修改
用户
字段(换句话说,使该字段只读)

相信我,我已经做了研究。我的
update
规则如下所示:

{
    name: "Buy milk",
    completed: false,
    user: "eYtGDHdfgSERewfqwEFfweE" // some user's uid
}
allow update: if request.auth.uid == resource.data.user
              //&& !request.writeFields.hasAny(["user"]);
              //&& !(request.writeFields.hasAny(["user"]));
              //&& !request.resource.data.keys().hasAny(["user"]);
              //&& !('user' in request.resource.data);
              //&& ('user' in request.resource.data) == false;
              //&& !('user' in request.writeFields);
上述(已注释掉的)工作中无一项。它们都会导致错误:
错误:缺少或权限不足。

但是

它变得更有趣了!因为如果我们比较上面的一些规则来获得积极的结果(aka
true
),它们就会起作用

例如,这个可以完美地工作(假设我们在请求中包含
user
字段):

但是这个不起作用(假设请求中不包含
用户
字段):

谁能解释一下这里发生了什么事?是否可能这实际上是Firestore中的一个bug?

在“编写云Firestore安全规则的条件”部分“数据验证”示例2

所以
request.resource.data.user==resource.data.user
应该为您工作吗?CMIIW

参考:

在“云Firestore安全规则的编写条件”部分“数据验证”示例2

所以
request.resource.data.user==resource.data.user
应该为您工作吗?CMIIW


Ref:

更新文档时,安全规则会将更新后的文档与安全规则的条件进行比较。这意味着,如果服务器上的文档中存在某个字段,但在更新中推送的数据中不存在该字段,则安全规则将从更新中的旧数据中看到该字段。例如:

在服务器上的文档存储中:

{
  reviewerID: sam123,
  title: "It sucks",
  description: "Because it does",
  rating: 1
}
然后您的更新是:

{
  description: "but actually it's not so bad",
  rating: 3
}
然后,安全规则在
request.resource.data
中看到的是:

{
  reviewerID: sam123,
  title: "It sucks",
  description: "but actually it's not so bad",
  rating: 3
}
这意味着,即使更新没有将更改推送到
reviewerID
title
中,这些字段也确实存在于您正在评估的数据中

要确保数据不变,您需要将新数据与旧数据进行比较:

request.resource.data.reviewerID==resource.data.reviewerID

该行:

!request.resource.data.keys().hasAny([“user”])

在阻止文档中存在数据方面是正确的。它不是允许它存在但使它不变的东西

见:

发件人:

以及:

发件人:


更新文档时,安全规则会将更新后的文档与安全规则的条件进行比较。这意味着,如果服务器上的文档中存在某个字段,但在更新中推送的数据中不存在该字段,则安全规则将从更新中的旧数据中看到该字段。例如:

在服务器上的文档存储中:

{
  reviewerID: sam123,
  title: "It sucks",
  description: "Because it does",
  rating: 1
}
然后您的更新是:

{
  description: "but actually it's not so bad",
  rating: 3
}
然后,安全规则在
request.resource.data
中看到的是:

{
  reviewerID: sam123,
  title: "It sucks",
  description: "but actually it's not so bad",
  rating: 3
}
这意味着,即使更新没有将更改推送到
reviewerID
title
中,这些字段也确实存在于您正在评估的数据中

要确保数据不变,您需要将新数据与旧数据进行比较:

request.resource.data.reviewerID==resource.data.reviewerID

该行:

!request.resource.data.keys().hasAny([“user”])

在阻止文档中存在数据方面是正确的。它不是允许它存在但使它不变的东西

见:

发件人:

以及:

发件人:


是的,我也用这个作为解决办法。但这样,您必须在每个请求中包含
user
字段,例如
set({user:firebase.auth().currentUser.uid,completed:true})
。如果你不这样做,你会得到一个错误。我希望能够完全不包含这个字段,例如
set({completed:true})
您可以使用set({completed:true},{merge:true})或update({completed:true})哦,伙计,您是对的。我非常关注那些安全规则,但实际上我使用了错误的方法。。。谢谢如果最初未设置
user
字段,则此解决方案不起作用。是的,我也将此用作解决方法。但这样,您必须在每个请求中包含
user
字段,例如
set({user:firebase.auth().currentUser.uid,completed:true})
。如果你不这样做,你会得到一个错误。我希望能够完全不包含这个字段,例如
set({completed:true})
您可以使用set({completed:true},{merge:true})或update({completed:true})哦,伙计,您是对的。我非常关注那些安全规则,但实际上我使用了错误的方法。。。谢谢如果最初未设置
用户
字段,则此解决方案不起作用。