Firestore安全规则:对请求使用hasOnly来检查是否仅更新特定字段

时间:2019-02-03 15:40:40

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

我正在设置Firestore安全规则,但是遇到一个问题,在这个问题中,我想限制使用hasOnly函数仅更新文档中的一个特定字段。问题是我一直在使用模拟器获得“被拒绝”的结果。我肯定在做一些简单的错误...我试图防止有人可以更新文档中除update_requested_time以外的其他字段,但是允许他们更新此特定字段。

在hasOnly()上使用Firestore文档中的示例— ['a', 'b'].hasOnly(['b', 'a']) == true时,规则将返回true。但是,当我使用自己的方法时,并没有这样做,因此我认为request.resource.data.keys()中出现了问题。

特定场景中的特定规则定位字段:

match /scenarios/{scenario} {
      allow read: if true;
      allow update: if request.auth.uid != null
        && request.resource.data.keys().hasOnly(['update_requested_time']) == true;

我正在发送的模拟器请求(通过身份验证更新):

{"__name__":"/databases/(default)/documents/scenarios/test1","data":{"update_requested_time":"2019-02-05T11:00:00.000Z"}}

我的完整规则:

service cloud.firestore {
  match /databases/{database}/documents {
    match /scenarios/{scenario} {
      allow read: if true;
      allow update: if request.auth.uid != null
        && request.resource.data.keys().hasOnly(['update_requested_time']) == true;
      match /comments/{comment} {
        allow read: if true;
        allow create: if request.auth.uid != null;
        allow delete,update: if request.auth.uid != null && request.auth.uid == resource.data.user;
      }
      match /outputs/{tile} {
        allow read: if true;
      }
      match /mutations/{tile} {
        allow read: if true;
        allow create,update: if request.auth.uid != null;
      }
    }
    match /users/{user} {
      allow read: if true;
      allow update: if request.auth.uid != null && request.auth.uid == user;
    }
  }
}

screenshot of firestore rules + simulator

3 个答案:

答案 0 :(得分:1)

request.resource.data不包含请求数据本身,而是包含写操作之后的资源的新版本。因此检查失败。

request.resource上的Firestore文档:

  

新资源值,仅在写入请求中出现。

答案 1 :(得分:1)

现在看来正确的方法是

request.resource.data.diff(resource.data).affectedKeys().hasOnly(["update_requested_time"])

this对话中找到

答案 2 :(得分:0)

也许我误解了这一点,但这不是一种解决方案,不能让您的规则在request.datarequest.resource.data之间进行深度比较以确认仅一个字段发生了变化吗?

也许有一种更清洁的方法,但是呢:

import _ from "lodash";

service cloud.firestore {
  match /databases/{database}/documents {

    function onlyRequestTimeChanged(currValue, newValue) {
      let newCopy = _.cloneDeep(newValue)
      newCopy.update_requested_time = currValue.update_requested_time

      return _.isEqual(currValue, newCopy)
    }

    match /scenarios/{scenario} {
      allow read: if true;
      allow update: if onlyRequestTimeChanged(request.resource,data, request.data)
  // ...
}
相关问题