【问题标题】:Firestore Rules to restrict write access to a specific field in a documentFirestore 规则,用于限制对文档中特定字段的写入权限
【发布时间】:2018-06-27 03:02:52
【问题描述】:

我正在使用 Stripe 进行付款。为此,我在 Firestore 中有以下数据模型:

Users/{userId}/payments/{document}

每个{document} 都是一个看起来像这样的对象:

{
  amount: 55
  token: {...}
  charge: {...}
}

用户必须能够编写token 字段(这是传递给服务器的内容),但我不希望用户能够编写charge 字段。

目前我的规则允许任何用户读取和写入此文档:

match /payments/{documents} {
  allow read, write: if request.auth.uid == userId;
}

什么 Firestore 规则可以实现我想要的安全性?

【问题讨论】:

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


【解决方案1】:

我相信以下内容会起作用,它允许客户更新除费用以外的字段,以及创建没有费用字段的文档。

service cloud.firestore {
  match /databases/{database}/documents {
    function valid_create() {
        return !(request.resource.data.keys().hasAll(["charge"]));
    }

    function valid_update() {
        return request.resource.data.charge == resource.data.charge
               || (valid_create()
                  && !(resource.data.keys().hasAll(["charge"])))
    }

    match /payments/{userId} {
        allow read: if request.auth.uid == userId;
        allow create: if request.auth.uid == userId
                        && valid_create(); 
        allow update: if request.auth.uid == userId
                        && valid_update(); 
    }
  }
}

【讨论】:

  • 您指的是userId,但它没有定义。为清楚起见,您可能需要将 {database} 更改为 {userId}
  • 很好的答案。我只会更新 valid_create|update 方法并检查管理员用户:return request.auth.token.role === 'admin' && !(request.resource...)
【解决方案2】:

Set type 和其他一些很酷的东西一起宣布了。


使用 Sets 确保文档只有字段“a”、“b”和“c”:

request.resource.data.keys().toSet() == ["a", "b", "c"].toSet()

同样,您可以确保文档只有指定的键,而没有其他键:

(request.resource.data.keys().toSet() - ["required","and","opt","keys"].toSet()).size == 0?`

【讨论】:

    【解决方案3】:

    接受的答案不适用于update,其中request.resource.data 返回已与现有数据合并的新地图。因此,request.resource.data.keys().hasAll([<<field>>]) 总是返回 true

    无论如何,对我有用的是使用.diff()

    function meta_is_modified() {
          return 'meta' in resource.data.diff(request.resource.data).affectedKeys();
        }
    

    这是另一个具有多个受保护字段的版本:

    function invalid_modification() {
      return resource.data.diff(request.resource.data).affectedKeys().hasAny(['field1', 'field2'].toSet());
    }
    

    【讨论】:

      【解决方案4】:

      感谢重定向到设置类型,它有很大帮助。 在我的项目中,我必须使用任何授权密钥(一个、多个或全部)验证请求,但没有额外的密钥。

      这就是我所做的;也许它可以帮助:

      (request.resource.data.keys().toSet().intersection(
          ["a","b","c","d"].toSet()
      )).size() == request.resource.data.keys().toSet().size();
      

      基本上,我比较了集合以及我的请求集密钥与包含授权密钥的集合之间的交集。由于我希望所有请求字段都匹配这些键,因此主集和交集必须相等。

      【讨论】:

        猜你喜欢
        • 2018-03-20
        • 1970-01-01
        • 2018-10-13
        • 1970-01-01
        • 2019-12-23
        • 1970-01-01
        • 1970-01-01
        • 2023-02-13
        • 1970-01-01
        相关资源
        最近更新 更多