了解Firestore安全规则-仅允许更新某些字段

时间:2020-05-30 23:55:16

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

我正在尝试使用Firestore安全规则,通过Flutter中的交易来编辑某些数据,如下所示:

  Future sendRequest(uidSend, uidRec, pid, title) async {
    final crSend = ChatRequest(uid: uidRec, pid: pid, title: title);
    var _lsSend = List();
    _lsSend.add(crSend.toJson());

    final crRec = ChatRequest(uid: uidSend, pid: pid, title: title);
    var _lsRec = List();
    _lsRec.add(crRec.toJson());

    final uMSendDocref = userMetadataCollection.document(uidSend);
    final uMRecDocref = userMetadataCollection.document(uidRec);

    Firestore.instance.runTransaction((transaction) async {
      await transaction.update(uMSendDocref, <String, dynamic>{
        "sentRequests": FieldValue.arrayUnion(
          _lsSend,
        ),
      });
      await transaction.update(uMRecDocref, <String, dynamic>{
        "receivedRequests": FieldValue.arrayUnion(
          _lsRec,
        ),
      });
    });
  }

请注意,user1正在尝试更新自己的数据以及user2的数据。但是,我只希望user1能够更新user2的单个字段。我这样制定Firestore规则:

    match /userMetadata/{uid} {
      allow read: if uid == request.auth.uid || uid == 'PREVIEW';
      allow write: if uid == request.auth.uid && uid != 'PREVIEW';
      match /receivedRequests {
        allow read: if uid == request.auth.uid;
        allow write: if request.auth != null && request.auth.uid != 'PREVIEW';
      }
      match /sentRequests {
        allow read: if uid == request.auth.uid;
        allow write: if request.auth != null && request.auth.uid != 'PREVIEW';
      }
    }

receivedRequests(和sentRequests)仅要求用户具有非null身份才能进行编辑,即,任何用户都应能够进行编辑。但是,运行事务时出现权限错误。这是为什么?也许我误解了Firestore的规则?也许交易正在尝试读取?有什么想法吗?

更新:

我尝试使用批处理:

  Future sendRequest(uidSend, uidRec, pid, title) async {
    //update own uM with post
    //update other uM with user

    final crSend = ChatRequest(uid: uidRec, pid: pid, title: title);
    var _lsSend = List();
    _lsSend.add(crSend.toJson());

    final crRec = ChatRequest(uid: uidSend, pid: pid, title: title);
    var _lsRec = List();
    _lsRec.add(crRec.toJson());

    final uMSendDocref = userMetadataCollection.document(uidSend);
    final uMRecDocref = userMetadataCollection.document(uidRec);

    var batch = Firestore.instance.batch();

    batch.updateData(uMSendDocref, <String, dynamic>{
      "sentRequests": FieldValue.arrayUnion(
        _lsSend,
      ),
    });

    batch.updateData(uMRecDocref, <String, dynamic>{
      "receivedRequests": FieldValue.arrayUnion(
        _lsRec,
      ),
    });

    return await batch.commit();
  }

仍然不起作用。 Firestore异常难以理解,或者存在严重的错误。

另一件事要注意:某些userMetadata当前可能没有正在更新的字段。

1 个答案:

答案 0 :(得分:1)

我只希望user1能够更新user2的单个字段。

仅允许更新某些字段的一般方法可以是使用request.resource.data检查diff resource.data

需要更新的示例文档有3个字段:名称,城市,常备余额。我们希望任何人都可以更改standingBalance,但只有相应的用户才能更改其姓名和城市。

以下示例考虑到user1应该具有对write的完整user1's sendRequest访问权限,并且只有single field updateuser2's receivedRequests的访问权限,在其他情况下不会有太大变化

match /userMetadata/{uid} {
  allow read: if uid == request.auth.uid || uid == 'PREVIEW';
  allow write: if uid == request.auth.uid && uid != 'PREVIEW';
  match /receivedRequests/{req} {
    allow read: if uid == request.auth.uid;
    allow write: if uid == request.auth.uid;
    allow update: if uid == request.auth.uid 
                 || (request.resource.data.keys().hasOnly(['name','city','standingBalance']) 
                     && request.resource.data.name == resource.data.name
                     && request.resource.data.city == resource.data.city
                     && request.resource.data.standingBalance != resource.data.standingBalance
                     && request.auth.uid != null
                    )
  }
  match /sentRequests/{req} {
    allow read: if uid == request.auth.uid;
    allow write: if request.auth != request.auth.uid || request.auth.uid != 'PREVIEW';
  }

使用hasOnly进行检查可确保没有其他密钥被添加到文档中。另外,我也不知道什么是“ PREVIEW”,因此请您自己验证规则。

在Firestore规则中使用fieldsChanged变量将是一个很好的功能请求;)