web-dev-qa-db-fra.com

Règles Firestore pour restreindre l'accès en écriture à un champ spécifique dans un document

J'utilise Stripe pour les paiements. Pour cela, j'ai le modèle de données suivant dans Firestore:

Users/{userId}/payments/{document}

chaque {document} est un objet qui ressemble à:

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

Les utilisateurs doivent pouvoir écrire le champ token (c'est ce qui est transmis au serveur), mais je ne souhaite pas que les utilisateurs puissent écrire le champ charge.

Actuellement, mes règles autorisent tout utilisateur à lire et à écrire dans ce document:

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

Quelles règles Firestore permettront d'atteindre la sécurité souhaitée?

8
astrojams1

Je pense que les solutions suivantes fonctionneraient, car elles permettraient aux clients de mettre à jour des champs à l'exception des frais, ainsi que de créer des documents sans le champ de frais.

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/{documents} {
        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(); 
    }
  }
}
14
Dan McGrath

Avec cette fonction unique, vous pouvez vérifier si des champs sont/ne sont pas créés/modifiés.

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

Usage:

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

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

Si vous souhaitez augmenter davantage votre sécurité pour permettre l'écriture uniquement dans le champ de jeton:

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