web-dev-qa-db-ja.com

ドキュメント内の特定のフィールドへの書き込みアクセスを制限するFirestoreルール

支払いに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ルールは何ですか?

17
astrojams1

次のようなものがうまくいくと思います。これにより、クライアントは請求以外のフィールドを更新したり、請求フィールドのないドキュメントを作成したりできます。

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(); 
    }
  }
}
25
Dan McGrath

この単一の関数を使用して、フィールドが作成または変更されているかどうかを確認できます。

function incomingDataHasFields(fields) {
    return (( 
        request.writeFields == null
        && request.resource.data.keys().hasAll(fields)
    ) || (
        request.writeFields != null
        && request.writeFields.hasAll(fields)
    ));
}

使用法:

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

    allow create, update:
        if request.auth.uid == userId
          && !incomingDataHasFields(['charge']);

セキュリティをさらに強化してトークンフィールドへの書き込みのみを許可する場合:

function incomingFieldsCountIs(count) {
    return ((
        request.writeFields == null
        && request.resource.data.keys().size() == count
    ) || (
        request.writeFields != null
        && request.writeFields.size() == count
    ));
}

...

    allow create, update:
        if request.auth.uid == userId
          && incomingFieldsCountIs(1)
          && incomingDataHasFields(['token'])
          && !incomingDataHasFields(['charge']);
0
Metu

セットタイプ が他のいくつかのクールなものとともに発表されました。


セットを使用して、ドキュメントにフィールド "a"、 "b"、および "c"のみがあることを確認します。

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

同様に、ドキュメントに指定されたキーのみがあり、他のキーはないことを確認できます。

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