【问题标题】:Making sense of Firestore Security Rules - only allowing update for certain fields理解 Firestore 安全规则 - 仅允许更新某些字段
【发布时间】:2020-09-18 10:39:57
【问题描述】:

我正在尝试使用 Firestore 安全规则来编辑一些数据,如下所示,在 Flutter 中使用 transaction

  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)只要求用户有一个非空的授权来编辑,即任何用户都应该能够编辑。但是,在运行事务时出现权限错误。这是为什么?也许我误解了 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 当前可能没有正在更新的字段。

【问题讨论】:

  • 一个事务确实首先进行读取。这就是它如何在事务处理函数中获取要修改的文档的初始内容。也许您想要批量写入,而不是先读取。
  • 或者,我可以只阅读文档的一部分吗?
  • 读取操作(在客户端 SDK 和安全规则中)始终读取整个文档。
  • 不要以为是这样。查看更新。
  • @OP 不是 receivedRequestssentRequests 集合吗? - 在这种情况下,“单字段”如何工作?

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


【解决方案1】:

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

仅允许更新某些字段的一般方法是检查 request.resource.dataresource.data 的差异。

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

下面的例子是考虑user1应该有完整的write访问user1's sendRequest&只有single field update访问user2'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 确保没有其他键被添加到文档中。另外,我不知道“预览”是什么,所以请自己验证规则。

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

【讨论】:

  • 你能测试一下吗?另外,如果可以的话,你会如何在一行中陈述你的最终目标? (例如,我想让 user1 能够更新他的所有字段,并且只更新 user2 文档的 1 个字段)
  • 我想使用匹配规则来完全匹配我想要的,而不会出现意外行为。是的,这可行,但不使用匹配规则。
  • 了解了一些东西,更新了我的答案,LMK 如果还有问题,很乐意提供帮助:)
猜你喜欢
  • 2020-09-22
  • 2020-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-28
  • 2017-10-08
  • 1970-01-01
相关资源
最近更新 更多