Catch up on everthing we announced at this year's Firebase Summit. Learn more

Conditions d'écriture pour les règles de sécurité Cloud Firestore

Ce guide se fonde sur les règles de sécurité structurante guide pour montrer comment ajouter des conditions à votre Cloud FireStore Règles de sécurité. Si vous n'êtes pas familier avec les bases du Cloud FireStore les règles de sécurité, consultez le faire démarrer guide.

Le bloc de construction principal des règles de sécurité Cloud Firestore est la condition. Une condition est une expression booléenne qui détermine si une opération particulière doit être autorisée ou refusée. Utilisez des règles de sécurité pour écrire des conditions qui vérifient l'authentification des utilisateurs, valident les données entrantes ou même accèdent à d'autres parties de votre base de données.

Authentification

L'un des modèles de règles de sécurité les plus courants consiste à contrôler l'accès en fonction de l'état d'authentification de l'utilisateur. Par exemple, votre application peut souhaiter autoriser uniquement les utilisateurs connectés à écrire des données :

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

Un autre modèle courant consiste à s'assurer que les utilisateurs ne peuvent lire et écrire que leurs propres données :

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

Si votre application utilise l' authentification Firebase ou Google Cloud Identity Platform , la request.auth variable contient les informations d'authentification pour le client demandant des données. Pour plus d' informations sur request.auth , consultez la documentation de référence .

La validation des données

De nombreuses applications stockent les informations de contrôle d'accès sous forme de champs sur les documents de la base de données. Les règles de sécurité Cloud Firestore peuvent autoriser ou refuser l'accès de manière dynamique en fonction des données du document :

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

La resource variable fait référence au document demandé et resource.data est une carte de tous les champs et les valeurs stockées dans le document. Pour plus d' informations sur la resource variables, consultez la documentation de référence .

Lors de l'écriture de données, vous souhaiterez peut-être comparer les données entrantes aux données existantes. Dans ce cas, si votre ruleset permet l'attente d' écriture, la request.resource variable contient l'état futur du document. Pour la update à request.resource update des opérations qui modifient seulement un sous - ensemble des champs de documents, la request.resource variable contiendra l'état de document en attente après l'opération. Vous pouvez vérifier les valeurs de champ dans request.resource pour éviter les mises à jour de données non désirées ou incohérentes:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

Accéder à d'autres documents

En utilisant la méthode get() et exists() fonctions, vos règles de sécurité peuvent évaluer les demandes entrantes contre d' autres documents dans la base de données. Le get() et exists() fonctionne à la fois attendre des chemins de documents spécifiés entièrement. Lors de l' utilisation des variables à des chemins de construct pour get() et exists() , vous devez échapper explicitement variables en utilisant la $(variable) syntaxe.

Dans l'exemple ci - dessous, la database de match /databases/{database}/documents database variable est capturée par l'instruction correspondance match /databases/{database}/documents de match /databases/{database}/documents de match /databases/{database}/documents et utilisés pour former le chemin:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid))

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
    }
  }
}

Pour les écritures, vous pouvez utiliser la getAfter() fonction pour accéder à l'état d'un document après une opération ou d'un lot d'écritures finalise mais avant les commits de transaction ou par lots. Comme get() , la getAfter() fonction prend un chemin de documents entièrement spécifié. Vous pouvez utiliser getAfter() pour définir des ensembles d'écritures qui doivent avoir lieu en même temps comme une transaction ou d'un lot.

Accéder aux limites d'appels

Il existe une limite d'appels d'accès aux documents par évaluation d'ensemble de règles :

  • 10 pour les demandes de document unique et les demandes de requête.
  • 20 pour les lectures multi-documents, les transactions et les écritures par lots. La limite précédente de 10 s'applique également à chaque opération.

    Par exemple, imaginez que vous créez une demande d'écriture groupée avec 3 opérations d'écriture et que vos règles de sécurité utilisent 2 appels d'accès au document pour valider chaque écriture. Dans ce cas, chaque écriture utilise 2 de ses 10 appels d'accès et la demande d'écriture par lots utilise 6 de ses 20 appels d'accès.

Le dépassement de l'une ou l'autre limite entraîne une erreur d'autorisation refusée. Certains appels d'accès aux documents peuvent être mis en cache et les appels mis en cache ne sont pas pris en compte dans les limites.

Pour une explication détaillée de la façon dont ces limites affectent les transactions et écritures par lots, consultez le guide pour la sécurisation des opérations atomiques .

Accéder aux appels et tarifs

L'utilisation de ces fonctions exécute une opération de lecture dans votre base de données, ce qui signifie que vous serez facturé pour la lecture des documents même si vos règles rejettent la demande. Voir Prix Nuage Firestore pour les informations de facturation plus spécifique.

Fonctions personnalisées

Au fur et à mesure que vos règles de sécurité deviennent plus complexes, vous souhaiterez peut-être encapsuler des ensembles de conditions dans des fonctions que vous pourrez réutiliser dans votre ensemble de règles. Les règles de sécurité prennent en charge les fonctions personnalisées. La syntaxe des fonctions personnalisées ressemble un peu à JavaScript, mais les fonctions de règles de sécurité sont écrites dans un langage spécifique à un domaine qui présente des limitations importantes :

  • Les fonctions peuvent contenir qu'un seul return déclaration. Ils ne peuvent pas contenir de logique supplémentaire. Par exemple, ils ne peuvent pas exécuter de boucles ou appeler des services externes.
  • Les fonctions peuvent accéder automatiquement aux fonctions et variables à partir de la portée dans laquelle elles sont définies. Par exemple, une fonction définie dans le service cloud.firestore portée a accès à la resource variable et des fonctions intégrées telles que get() et exists() .
  • Les fonctions peuvent appeler d'autres fonctions mais ne peuvent pas se reproduire. La profondeur totale de la pile d'appels est limitée à 10.
  • Dans la version des règles v2 , les fonctions peuvent définir des variables à l' aide du let mot - clé. Les fonctions peuvent avoir jusqu'à 10 liaisons let, mais doivent se terminer par une instruction return.

Une fonction est définie par la function mot - clé et prend zéro ou plusieurs arguments. Par exemple, vous pouvez combiner les deux types de conditions utilisées dans les exemples ci-dessus en une seule fonction :

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

L'utilisation de fonctions dans vos règles de sécurité les rend plus faciles à gérer à mesure que la complexité de vos règles augmente.

Les règles ne sont pas des filtres

Une fois que vous avez sécurisé vos données et commencé à écrire des requêtes, gardez à l'esprit que les règles de sécurité ne sont pas des filtres. Vous ne pouvez pas écrire une requête pour tous les documents d'une collection et vous attendre à ce que Cloud Firestore renvoie uniquement les documents auxquels le client actuel est autorisé à accéder.

Par exemple, prenons la règle de sécurité suivante :

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Refusé: Cette règle rejette la requête suivante car le jeu de résultats peut inclure des documents où la visibility est pas public :

la toile
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

Permis: Cette règle permet à la requête suivante car where("visibility", "==", "public") la where("visibility", "==", "public") clause garantit que l'ensemble de résultats satisfait la condition de la règle:

la toile
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

Les règles de sécurité de Cloud Firestore évaluent chaque requête par rapport à son résultat potentiel et échouent à la requête si elle peut renvoyer un document que le client n'est pas autorisé à lire. Les requêtes doivent respecter les contraintes définies par vos règles de sécurité. Pour en savoir plus sur les règles de sécurité et les requêtes, voir l' interrogation de données en toute sécurité .

Prochaines étapes