【问题标题】:Firestore Security Rules - how to prevent modification of a certain fieldFirestore 安全规则 - 如何防止修改某个字段
【发布时间】:2018-09-15 10:44:15
【问题描述】:

假设我们有一个名为 todos 的 Firestore 集合,其中每个待办事项看起来像这样:

{
    name: "Buy milk",
    completed: false,
    user: "eYtGDHdfgSERewfqwEFfweE" // some user's uid
}

现在,我想在更新期间防止修改 user 字段(换句话说 - 将此字段设为只读)。

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

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);

没有上述(注释掉)工作。它们都导致错误:Error: Missing or insufficient permissions.

但是……

它变得更加有趣!因为如果我们比较上述一些规则以获得积极的结果(又名true),它们就会起作用!

例如,这个完美运行(假设我们在请求中包含user 字段):

allow update: if request.resource.data.keys().hasAny(["user"]) == true;

但是这个不起作用(假设我们没有在请求中包含user 字段):

allow update: if request.resource.data.keys().hasAny(["user"]) == false;

谁能解释一下这里发生了什么?这可能实际上是 Firestore 中的一个错误吗?

【问题讨论】:

    标签: firebase google-cloud-firestore firebase-security


    【解决方案1】:

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

    service cloud.firestore {
      match /databases/{database}/documents {
        // Make sure all cities have a positive population and
        // the name is not changed
        match /cities/{city} {
          allow update: if request.resource.data.population > 0
                        && request.resource.data.name == resource.data.name;
        }
      }
    }
    

    所以request.resource.data.user == resource.data.user 应该适合你吗? CMIIW

    参考:https://firebase.google.com/docs/firestore/security/rules-conditions#data_validation

    【讨论】:

    • 是的,我也使用它作为我的解决方法。但是这样您必须在每个请求中包含user 字段,例如set({user: firebase.auth().currentUser.uid, completed: true})。如果你不这样做,你会得到一个错误。我希望能够完全不包括这个字段,例如set({completed: true})
    • 你可以使用 set({completed: true}, {merge: true}) 或 update({completed: true})
    • 天哪,你是对的。我非常关注那些安全规则,但我实际上使用了错误的方法......谢谢!
    • 如果最初未设置 user 字段,则此解决方案不起作用。
    • 如果您使用合并进行设置,您可以将字段留空以保留其当前值,这是否会失败,因为 request.resource 将为 nil 而 resource.data 将为 nonnil?还是规则在执行规则时自动匹配合并写入中的未设置字段?
    【解决方案2】:

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

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

    {
      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
    }
    

    这意味着即使更新没有将更改推送到 reviewerIDtitle,这些字段确实存在于您正在评估的数据中。

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

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

    行:

    !request.resource.data.keys().hasAny(["user"]);

    在防止数据存在于文档中是正确的。它不是允许它存在但使其不可变的东西。

    见:

    service cloud.firestore {
      match /databases/{database}/documents {
        // Make sure all cities have a positive population and
        // the name is not changed
        match /cities/{city} {
          allow update: if request.resource.data.population > 0
                        && request.resource.data.name == resource.data.name;
        }
      }
    }
    

    发件人:

    https://firebase.google.com/docs/firestore/security/rules-conditions#data_validation

    和:

    service cloud.firestore {
      match /databases/{database}/documents {
        // Allow the user to create a document only if that document does *not*
        // contain an average_score or rating_count field.
        match /restaurant/{restId} {
          allow create: if (!request.resource.data.keys().hasAny(
            ['average_score', 'rating_count']));
        }
      }
    }
    

    发件人:

    https://firebase.google.com/docs/firestore/security/rules-fields#forbidding_specific_fields_in_new_documents

    【讨论】:

      猜你喜欢
      • 2018-06-18
      • 2020-01-10
      • 2020-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-18
      相关资源
      最近更新 更多