Les règles de sécurité Firebase exploitent des langages flexibles, puissants et personnalisés qui prennent en charge un large éventail de complexité et de granularité. Vous pouvez rendre vos règles aussi spécifiques ou générales que cela est logique pour votre application. Les règles de base de données en temps réel utilisent une syntaxe qui ressemble à JavaScript dans une structure JSON. Les règles Cloud Firestore et Cloud Storage utilisent un langage basé sur le langage CEL (Common Expression Language) , qui s'appuie sur le CEL avec match et d' allow qui prennent en charge l'accès accordé sous condition.
Cependant, comme il s’agit de langages personnalisés, il existe une courbe d’apprentissage. Utilisez ce guide pour mieux comprendre le langage des règles à mesure que vous approfondissez des règles plus complexes.
Sélectionnez un produit pour en savoir plus sur ses règles.
Structure basique
Cloud Firestore
Les règles de sécurité Firebase dans Cloud Firestore et Cloud Storage utilisent la structure et la syntaxe suivantes :
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
Il est important de comprendre les concepts clés suivants lorsque vous élaborez les règles :
- Requête : la ou les méthodes invoquées dans l'instruction
allow. Ce sont des méthodes que vous autorisez à exécuter. Les méthodes standard sont :get,list,create,updateetdelete. Les méthodes pratiquesreadetwritepermettent un large accès en lecture et en écriture sur la base de données ou le chemin de stockage spécifié. - Chemin : la base de données ou l'emplacement de stockage, représenté sous la forme d'un chemin URI.
- Règle : l'instruction
allow, qui inclut une condition qui autorise une demande si elle est évaluée comme vraie.
Chacun de ces concepts est décrit plus en détail ci-dessous.
Stockage en ligne
Les règles de sécurité Firebase dans Cloud Firestore et Cloud Storage utilisent la structure et la syntaxe suivantes :
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
Il est important de comprendre les concepts clés suivants lorsque vous élaborez les règles :
- Requête : la ou les méthodes invoquées dans l'instruction
allow. Ce sont des méthodes que vous autorisez à exécuter. Les méthodes standard sont :get,list,create,updateetdelete. Les méthodes pratiquesreadetwritepermettent un large accès en lecture et en écriture sur la base de données ou le chemin de stockage spécifié. - Chemin : la base de données ou l'emplacement de stockage, représenté sous la forme d'un chemin URI.
- Règle : l'instruction
allow, qui inclut une condition qui autorise une demande si elle est évaluée comme vraie.
Chacun de ces concepts est décrit plus en détail ci-dessous.
Base de données en temps réel
Dans Realtime Database, les règles de sécurité Firebase sont constituées d'expressions de type JavaScript contenues dans un document JSON.
Ils utilisent la syntaxe suivante :
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
Il y a trois éléments de base dans la règle :
- Chemin : l'emplacement de la base de données. Cela reflète la structure JSON de votre base de données.
- Requête : ce sont les méthodes utilisées par la règle pour accorder l'accès. Les règles
readetwriteaccordent un large accès en lecture et en écriture, tandis que les règlesvalidateagissent comme une vérification secondaire pour accorder l'accès en fonction des données entrantes ou existantes. - Condition : condition qui autorise une requête si elle est évaluée comme vraie.
Constructions de règles
Cloud Firestore
Les éléments de base d'une règle dans Cloud Firestore et Cloud Storage sont les suivants :
- La déclaration
service: déclare le produit Firebase auquel les règles s'appliquent. - Le bloc
match: définit un chemin dans la base de données ou le compartiment de stockage auquel les règles s'appliquent. - L'instruction
allow: fournit des conditions d'octroi de l'accès, différenciées par des méthodes. Les méthodes prises en charge incluent :get,list,create,update,deleteet les méthodes pratiquesreadetwrite. - Déclarations
functionfacultatives : offrent la possibilité de combiner et d'encapsuler des conditions pour une utilisation dans plusieurs règles.
Le service contient un ou plusieurs blocs match avec des instructions allow qui fournissent des conditions accordant l'accès aux requêtes. Les variables request et resource peuvent être utilisées dans les conditions de règle. Le langage des règles de sécurité Firebase prend également en charge les déclarations function .
Version syntaxique
L'instruction syntax indique la version du langage Firebase Rules utilisée pour écrire la source. La dernière version du langage est v2 .
rules_version = '2';
service cloud.firestore {
...
}
Si aucune instruction rules_version n'est fournie, vos règles seront évaluées à l'aide du moteur v1 .
Service
La déclaration service définit à quel produit ou service Firebase vos règles s'appliquent. Vous ne pouvez inclure qu'une seule déclaration service par fichier source.
Cloud Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Stockage en ligne
service firebase.storage {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Si vous définissez des règles pour Cloud Firestore et Cloud Storage à l'aide de Firebase CLI, vous devrez les conserver dans des fichiers distincts.
Correspondre
Un bloc match déclare un modèle path qui correspond au chemin de l'opération demandée (le request.path entrant). Le corps de la match doit avoir un ou plusieurs blocs match imbriqués, des instructions allow ou des déclarations function . Le chemin dans les blocs match imbriqués est relatif au chemin dans le bloc match parent.
Le modèle path est un nom de type répertoire qui peut inclure des variables ou des caractères génériques. Le modèle path permet des correspondances de segments à chemin unique et de segments à chemins multiples. Toutes les variables liées à un path sont visibles dans la portée match ou dans toute portée imbriquée où le path est déclaré.
Les correspondances avec un modèle path peuvent être partielles ou complètes :
- Correspondances partielles : le modèle
pathest une correspondance de préfixe derequest.path. - Correspondances complètes : le modèle
pathcorrespond à l'intégralitérequest.path.
Lorsqu'une correspondance complète est établie, les règles du bloc sont évaluées. Lorsqu'une correspondance partielle est établie, les règles match imbriquées sont testées pour voir si un path imbriqué complètera la correspondance.
Les règles de chaque match complète sont évaluées pour déterminer s'il convient d'autoriser la demande. Si une règle correspondante accorde l’accès, la demande est autorisée. Si aucune règle de correspondance n'accorde l'accès, la demande est refusée.
// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
// Partial match.
match /example/{singleSegment} { // `singleSegment` == 'hello'
allow write; // Write rule not evaluated.
// Complete match.
match /nested/path { // `singleSegment` visible in scope.
allow read; // Read rule is evaluated.
}
}
// Complete match.
match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
allow read; // Read rule is evaluated.
}
}
Comme le montre l'exemple ci-dessus, les déclarations path prennent en charge les variables suivantes :
- Caractère générique à segment unique : une variable générique est déclarée dans un chemin en enveloppant une variable entre accolades :
{variable}. Cette variable est accessible dans l'instructionmatchsous forme destring. - Caractère générique récursif : le caractère générique récursif ou multi-segments correspond à plusieurs segments de chemin au niveau ou en dessous d'un chemin. Ce caractère générique correspond à tous les chemins situés sous l'emplacement auquel vous l'avez défini. Vous pouvez le déclarer en ajoutant la chaîne
=**à la fin de votre variable de segment :{variable=**}. Cette variable est accessible dans l'instructionmatchen tant qu'objetpath.
Permettre
Le bloc match contient une ou plusieurs instructions allow . Ce sont vos véritables règles. Vous pouvez appliquer des règles allow à une ou plusieurs méthodes. Les conditions d'une instruction allow doivent être évaluées comme vraies pour que Cloud Firestore ou Cloud Storage accède à toute demande entrante. Vous pouvez également écrire des instructions allow sans conditions, par exemple, allow read . Toutefois, si l'instruction allow n'inclut pas de condition, elle autorise toujours la requête pour cette méthode.
Si l’une des règles allow de la méthode est satisfaite, la demande est autorisée. De plus, si une règle plus large accorde l'accès, les règles accordent l'accès et ignorent les règles plus granulaires susceptibles de limiter l'accès.
Prenons l'exemple suivant, dans lequel n'importe quel utilisateur peut lire ou supprimer n'importe lequel de ses propres fichiers. Une règle plus granulaire n'autorise les écritures que si l'utilisateur demandant l'écriture est propriétaire du fichier et que le fichier est au format PNG. Un utilisateur peut supprimer tous les fichiers du sous-chemin, même s'il ne s'agit pas de fichiers PNG, car la règle précédente le permet.
service firebase.storage {
// Allow the requestor to read or delete any resource on a path under the
// user directory.
match /users/{userId}/{anyUserFile=**} {
allow read, delete: if request.auth != null && request.auth.uid == userId;
}
// Allow the requestor to create or update their own images.
// When 'request.method' == 'delete' this rule and the one matching
// any path under the user directory would both match and the `delete`
// would be permitted.
match /users/{userId}/images/{imageId} {
// Whether to permit the request depends on the logical OR of all
// matched rules. This means that even if this rule did not explicitly
// allow the 'delete' the earlier rule would have.
allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
}
}
Méthode
Chaque instruction allow inclut une méthode qui accorde l'accès aux requêtes entrantes de la même méthode.
| Méthode | Type de demande |
|---|---|
| Méthodes pratiques | |
read | Tout type de demande de lecture |
write | Tout type de demande d'écriture |
| Méthodes standards | |
get | Demandes de lecture de documents ou de fichiers uniques |
list | Lire les demandes de requêtes et de collections |
create | Écrire de nouveaux documents ou fichiers |
update | Écrire dans des documents de base de données existants ou mettre à jour les métadonnées des fichiers |
delete | Suprimmer les données |
Vous ne pouvez pas chevaucher les méthodes de lecture dans le même bloc match ou les méthodes d'écriture en conflit dans la même déclaration path .
Par exemple, les règles suivantes échoueraient :
service bad.example {
match /rules/with/overlapping/methods {
// This rule allows reads to all authenticated users
allow read: if request.auth != null;
match another/subpath {
// This secondary, more specific read rule causes an error
allow get: if request.auth != null && request.auth.uid == "me";
// Overlapping write methods in the same path cause an error as well
allow write: if request.auth != null;
allow create: if request.auth != null && request.auth.uid == "me";
}
}
}
Fonction
À mesure que vos règles de sécurité deviennent plus complexes, vous souhaiterez peut-être regrouper 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 au domaine qui présente certaines limitations importantes :
- Les fonctions ne peuvent contenir qu'une seule instruction
return. Ils ne peuvent contenir aucune logique supplémentaire. Par exemple, ils ne peuvent pas exécuter de boucles ni appeler des services externes. - Les fonctions peuvent accéder automatiquement aux fonctions et aux variables à partir de la portée dans laquelle elles sont définies. Par exemple, une fonction définie dans la portée du
service cloud.firestorea accès à la variableresourceet aux fonctions intégrées telles queget()etexists(). - Les fonctions peuvent appeler d'autres fonctions mais ne peuvent pas récidiver. La profondeur totale de la pile d’appels est limitée à 20.
- Dans la version
v2des règles, les fonctions peuvent définir des variables à l'aide du mot-clélet. Les fonctions peuvent avoir jusqu'à 10 liaisons let, mais doivent se terminer par une instruction return.
Une fonction est définie avec le mot-clé function et prend zéro ou plusieurs arguments. Par exemple, vous souhaiterez peut-être combiner les deux types de conditions utilisés 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();
}
}
}
Voici un exemple montrant les arguments de fonction et les affectations de let. Les instructions d'affectation Let doivent être séparées par des points-virgules.
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
return isAuthor || isAdmin;
}
Notez comment l'affectation isAdmin applique une recherche dans la collection admins. Pour une évaluation paresseuse sans nécessiter de recherches inutiles, profitez de la nature de court-circuit de && (AND) et || (OR) comparaisons pour appeler une deuxième fonction uniquement si isAuthor s'avère vrai (pour les comparaisons && ) ou faux (pour les comparaisons || ).
function isAdmin(userId) {
return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
// `||` is short-circuiting; isAdmin called only if isAuthor == false.
return isAuthor || isAdmin(userId);
}
L'utilisation de fonctions dans vos règles de sécurité les rend plus faciles à maintenir à mesure que la complexité de vos règles augmente.
Stockage en ligne
Les éléments de base d'une règle dans Cloud Firestore et Cloud Storage sont les suivants :
- La déclaration
service: déclare le produit Firebase auquel les règles s'appliquent. - Le bloc
match: définit un chemin dans la base de données ou le compartiment de stockage auquel les règles s'appliquent. - L'instruction
allow: fournit des conditions d'octroi de l'accès, différenciées par des méthodes. Les méthodes prises en charge incluent :get,list,create,update,deleteet les méthodes pratiquesreadetwrite. - Déclarations
functionfacultatives : offrent la possibilité de combiner et d'encapsuler des conditions pour une utilisation dans plusieurs règles.
Le service contient un ou plusieurs blocs match avec des instructions allow qui fournissent des conditions accordant l'accès aux requêtes. Les variables request et resource peuvent être utilisées dans les conditions de règle. Le langage des règles de sécurité Firebase prend également en charge les déclarations function .
Version syntaxique
L'instruction syntax indique la version du langage Firebase Rules utilisée pour écrire la source. La dernière version du langage est v2 .
rules_version = '2';
service cloud.firestore {
...
}
Si aucune instruction rules_version n'est fournie, vos règles seront évaluées à l'aide du moteur v1 .
Service
La déclaration service définit à quel produit ou service Firebase vos règles s'appliquent. Vous ne pouvez inclure qu'une seule déclaration service par fichier source.
Cloud Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Stockage en ligne
service firebase.storage {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Si vous définissez des règles pour Cloud Firestore et Cloud Storage à l'aide de Firebase CLI, vous devrez les conserver dans des fichiers distincts.
Correspondre
Un bloc match déclare un modèle path qui correspond au chemin de l'opération demandée (le request.path entrant). Le corps de la match doit avoir un ou plusieurs blocs match imbriqués, des instructions allow ou des déclarations function . Le chemin dans les blocs match imbriqués est relatif au chemin dans le bloc match parent.
Le modèle path est un nom de type répertoire qui peut inclure des variables ou des caractères génériques. Le modèle path permet des correspondances de segments à chemin unique et de segments à chemins multiples. Toutes les variables liées à un path sont visibles dans la portée match ou dans toute portée imbriquée où le path est déclaré.
Les correspondances avec un modèle path peuvent être partielles ou complètes :
- Correspondances partielles : le modèle
pathest une correspondance de préfixe derequest.path. - Correspondances complètes : le modèle
pathcorrespond à l'intégralitérequest.path.
Lorsqu'une correspondance complète est établie, les règles du bloc sont évaluées. Lorsqu'une correspondance partielle est établie, les règles match imbriquées sont testées pour voir si un path imbriqué complètera la correspondance.
Les règles de chaque match complète sont évaluées pour déterminer s'il convient d'autoriser la demande. Si une règle correspondante accorde l’accès, la demande est autorisée. Si aucune règle de correspondance n'accorde l'accès, la demande est refusée.
// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
// Partial match.
match /example/{singleSegment} { // `singleSegment` == 'hello'
allow write; // Write rule not evaluated.
// Complete match.
match /nested/path { // `singleSegment` visible in scope.
allow read; // Read rule is evaluated.
}
}
// Complete match.
match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
allow read; // Read rule is evaluated.
}
}
Comme le montre l'exemple ci-dessus, les déclarations path prennent en charge les variables suivantes :
- Caractère générique à segment unique : une variable générique est déclarée dans un chemin en enveloppant une variable entre accolades :
{variable}. Cette variable est accessible dans l'instructionmatchsous forme destring. - Caractère générique récursif : le caractère générique récursif ou multi-segments correspond à plusieurs segments de chemin au niveau ou en dessous d'un chemin. Ce caractère générique correspond à tous les chemins situés sous l'emplacement auquel vous l'avez défini. Vous pouvez le déclarer en ajoutant la chaîne
=**à la fin de votre variable de segment :{variable=**}. Cette variable est accessible dans l'instructionmatchen tant qu'objetpath.
Permettre
Le bloc match contient une ou plusieurs instructions allow . Ce sont vos véritables règles. Vous pouvez appliquer des règles allow à une ou plusieurs méthodes. Les conditions d'une instruction allow doivent être évaluées comme vraies pour que Cloud Firestore ou Cloud Storage accède à toute demande entrante. Vous pouvez également écrire des instructions allow sans conditions, par exemple, allow read . Toutefois, si l'instruction allow n'inclut pas de condition, elle autorise toujours la requête pour cette méthode.
Si l’une des règles allow de la méthode est satisfaite, la demande est autorisée. De plus, si une règle plus large accorde l'accès, les règles accordent l'accès et ignorent les règles plus granulaires susceptibles de limiter l'accès.
Prenons l'exemple suivant, dans lequel n'importe quel utilisateur peut lire ou supprimer n'importe lequel de ses propres fichiers. Une règle plus granulaire n'autorise les écritures que si l'utilisateur demandant l'écriture est propriétaire du fichier et que le fichier est au format PNG. Un utilisateur peut supprimer tous les fichiers du sous-chemin, même s'il ne s'agit pas de fichiers PNG, car la règle précédente le permet.
service firebase.storage {
// Allow the requestor to read or delete any resource on a path under the
// user directory.
match /users/{userId}/{anyUserFile=**} {
allow read, delete: if request.auth != null && request.auth.uid == userId;
}
// Allow the requestor to create or update their own images.
// When 'request.method' == 'delete' this rule and the one matching
// any path under the user directory would both match and the `delete`
// would be permitted.
match /users/{userId}/images/{imageId} {
// Whether to permit the request depends on the logical OR of all
// matched rules. This means that even if this rule did not explicitly
// allow the 'delete' the earlier rule would have.
allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
}
}
Méthode
Chaque instruction allow inclut une méthode qui accorde l'accès aux demandes entrantes de la même méthode.
| Méthode | Type de demande |
|---|---|
| Méthodes pratiques | |
read | Tout type de demande de lecture |
write | Tout type de demande d'écriture |
| Méthodes standards | |
get | Demandes de lecture de documents ou de fichiers uniques |
list | Lire les demandes de requêtes et de collections |
create | Écrire de nouveaux documents ou fichiers |
update | Écrire dans des documents de base de données existants ou mettre à jour les métadonnées des fichiers |
delete | Suprimmer les données |
Vous ne pouvez pas chevaucher les méthodes de lecture dans le même bloc match ou les méthodes d'écriture en conflit dans la même déclaration path .
Par exemple, les règles suivantes échoueraient :
service bad.example {
match /rules/with/overlapping/methods {
// This rule allows reads to all authenticated users
allow read: if request.auth != null;
match another/subpath {
// This secondary, more specific read rule causes an error
allow get: if request.auth != null && request.auth.uid == "me";
// Overlapping write methods in the same path cause an error as well
allow write: if request.auth != null;
allow create: if request.auth != null && request.auth.uid == "me";
}
}
}
Fonction
À mesure que vos règles de sécurité deviennent plus complexes, vous souhaiterez peut-être regrouper 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 au domaine qui présente certaines limitations importantes :
- Les fonctions ne peuvent contenir qu'une seule instruction
return. Ils ne peuvent contenir aucune logique supplémentaire. Par exemple, ils ne peuvent pas exécuter de boucles ni appeler des services externes. - Les fonctions peuvent accéder automatiquement aux fonctions et aux variables à partir de la portée dans laquelle elles sont définies. Par exemple, une fonction définie dans la portée du
service cloud.firestorea accès à la variableresourceet aux fonctions intégrées telles queget()etexists(). - Les fonctions peuvent appeler d'autres fonctions mais ne peuvent pas récidiver. La profondeur totale de la pile d’appels est limitée à 20.
- Dans la version
v2des règles, les fonctions peuvent définir des variables à l'aide du mot-clélet. Les fonctions peuvent avoir jusqu'à 10 liaisons let, mais doivent se terminer par une instruction return.
Une fonction est définie avec le mot-clé function et prend zéro ou plusieurs arguments. Par exemple, vous souhaiterez peut-être combiner les deux types de conditions utilisés 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();
}
}
}
Voici un exemple montrant les arguments de fonction et les affectations de let. Les instructions d'affectation Let doivent être séparées par des points-virgules.
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
return isAuthor || isAdmin;
}
Notez comment l'affectation isAdmin applique une recherche dans la collection admins. Pour une évaluation paresseuse sans nécessiter de recherches inutiles, profitez de la nature de court-circuit de && (AND) et || (OR) comparaisons pour appeler une deuxième fonction uniquement si isAuthor s'avère vrai (pour les comparaisons && ) ou faux (pour les comparaisons || ).
function isAdmin(userId) {
return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
// `||` is short-circuiting; isAdmin called only if isAuthor == false.
return isAuthor || isAdmin(userId);
}
L'utilisation de fonctions dans vos règles de sécurité les rend plus faciles à maintenir à mesure que la complexité de vos règles augmente.
Base de données en temps réel
Comme indiqué ci-dessus, les règles de base de données en temps réel comprennent trois éléments de base : l'emplacement de la base de données en tant que miroir de la structure JSON de la base de données, le type de demande et la condition accordant l'accès.
Emplacement de la base de données
La structure de vos règles doit suivre la structure des données que vous avez stockées dans votre base de données. Par exemple, dans une application de chat avec une liste de messages, vous pourriez avoir des données ressemblant à ceci :
{
"messages": {
"message0": {
"content": "Hello",
"timestamp": 1405704370369
},
"message1": {
"content": "Goodbye",
"timestamp": 1405704395231
},
...
}
}
Vos règles doivent refléter cette structure. Par exemple:
{
"rules": {
"messages": {
"$message": {
// only messages from the last ten minutes can be read
".read": "data.child('timestamp').val() > (now - 600000)",
// new messages must have a string content and a number timestamp
".validate": "newData.hasChildren(['content', 'timestamp']) &&
newData.child('content').isString() &&
newData.child('timestamp').isNumber()"
}
}
}
}
Comme le montre l'exemple ci-dessus, les règles de base de données en temps réel prennent en charge une variable $location pour faire correspondre les segments de chemin. Utilisez le préfixe $ devant votre segment de chemin pour faire correspondre votre règle à tous les nœuds enfants le long du chemin.
{
"rules": {
"rooms": {
// This rule applies to any child of /rooms/, the key for each room id
// is stored inside $room_id variable for reference
"$room_id": {
"topic": {
// The room's topic can be changed if the room id has "public" in it
".write": "$room_id.contains('public')"
}
}
}
}
}
Vous pouvez également utiliser la $variable en parallèle avec des noms de chemin constants.
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}
Méthode
Dans Realtime Database, il existe trois types de règles. Deux de ces types de règles ( read et write ) s'appliquent à la méthode d'une requête entrante. Le type de règle validate applique les structures de données et valide le format et le contenu des données. Les règles exécutent les règles .validate après avoir vérifié qu'une règle .write accorde l'accès.
| Types de règles | |
|---|---|
| .lire | Décrit si et quand les données peuvent être lues par les utilisateurs. |
| .écrire | Décrit si et quand l’écriture des données est autorisée. |
| .valider | Définit à quoi ressemblera une valeur correctement formatée, si elle possède des attributs enfants et le type de données. |
Par défaut, s'il n'y a pas de règle l'autorisant, l'accès à un chemin est refusé.
Conditions de construction
Cloud Firestore
Une condition est une expression booléenne qui détermine si une opération particulière doit être autorisée ou refusée. Les variables request et resource fournissent un contexte pour ces conditions.
La variable request
La variable request comprend les champs suivants et les informations correspondantes :
request.auth
Un jeton Web JSON (JWT) qui contient les informations d'authentification de Firebase Authentication. le jeton auth contient un ensemble de revendications standard et toutes les revendications personnalisées que vous créez via l'authentification Firebase. En savoir plus sur les règles de sécurité et l'authentification Firebase .
request.method
La request.method peut être l’une des méthodes standard ou une méthode personnalisée. Les méthodes pratiques read et write existent également pour simplifier les règles d'écriture qui s'appliquent respectivement à toutes les méthodes standard en lecture seule ou à toutes les méthodes standard en écriture seule.
request.params
Les request.params incluent toutes les données non spécifiquement liées à request.resource qui pourraient être utiles pour l'évaluation. En pratique, cette carte doit être vide pour toutes les méthodes standard et doit contenir des données hors ressources pour les méthodes personnalisées. Les services doivent veiller à ne pas renommer ou modifier le type des clés et valeurs présentées en tant que paramètres.
request.path
Le request.path est le chemin de la resource cible. Le chemin est relatif au service. Les segments de chemin contenant des caractères non sécurisés pour les URL, tels que / sont codés en URL.
La variable resource
La resource est la valeur actuelle au sein du service représentée sous forme de carte de paires clé-valeur. Le référencement d’une resource dans une condition entraînera au plus une lecture de la valeur du service. Cette recherche sera prise en compte dans tout quota lié au service pour la ressource. Pour les requêtes get , la resource ne sera prise en compte dans le quota qu’en cas de refus.
Opérateurs et priorité des opérateurs
Utilisez le tableau ci-dessous comme référence pour les opérateurs et leur priorité correspondante dans les règles pour Cloud Firestore et Cloud Storage.
Étant donné des expressions arbitraires a et b , un champ f et un index i .
| Opérateur | Description | Associativité |
|---|---|---|
a[i] a() af | Index, appel, accès terrain | de gauche à droite | !a -a | Négation unaire | de droite à gauche |
a/ba%ba*b | Opérateurs multiplicatifs | de gauche à droite |
a+b ab | Opérateurs additifs | de gauche à droite |
a>ba>=ba | Opérateurs relationnels | de gauche à droite |
a in b | Existence dans une liste ou une carte | de gauche à droite |
a is type | Comparaison de types, où type peut être bool, int, float, number, string, list, map, timestamp, duration, path ou latlng | de gauche à droite |
a==ba!=b | Opérateurs de comparaison | de gauche à droite | a && b | ET conditionnel | de gauche à droite |
a || b | OU conditionnel | de gauche à droite |
a ? true_value : false_value | Expression ternaire | de gauche à droite |
Stockage en ligne
Une condition est une expression booléenne qui détermine si une opération particulière doit être autorisée ou refusée. Les variables request et resource fournissent un contexte pour ces conditions.
La variable request
La variable request comprend les champs suivants et les informations correspondantes :
request.auth
Un jeton Web JSON (JWT) qui contient les informations d'authentification de Firebase Authentication. le jeton auth contient un ensemble de revendications standard et toutes les revendications personnalisées que vous créez via l'authentification Firebase. En savoir plus sur les règles de sécurité et l'authentification Firebase .
request.method
La request.method peut être l’une des méthodes standard ou une méthode personnalisée. Les méthodes pratiques read et write existent également pour simplifier les règles d'écriture qui s'appliquent respectivement à toutes les méthodes standard en lecture seule ou à toutes les méthodes standard en écriture seule.
request.params
Les request.params incluent toutes les données non spécifiquement liées à request.resource qui pourraient être utiles pour l’évaluation. En pratique, cette carte doit être vide pour toutes les méthodes standard et doit contenir des données hors ressources pour les méthodes personnalisées. Les services doivent veiller à ne pas renommer ou modifier le type des clés et valeurs présentées en tant que paramètres.
request.path
Le request.path est le chemin de la resource cible. Le chemin est relatif au service. Les segments de chemin contenant des caractères non sécurisés pour les URL, tels que / sont codés en URL.
La variable resource
La resource est la valeur actuelle au sein du service représentée sous forme de carte de paires clé-valeur. Le référencement d’une resource dans une condition entraînera au plus une lecture de la valeur du service. Cette recherche sera prise en compte dans tout quota lié au service pour la ressource. Pour les requêtes get , la resource ne sera prise en compte dans le quota qu’en cas de refus.
Opérateurs et priorité des opérateurs
Utilisez le tableau ci-dessous comme référence pour les opérateurs et leur priorité correspondante dans les règles pour Cloud Firestore et Cloud Storage.
Étant donné des expressions arbitraires a et b , un champ f et un index i .
| Opérateur | Description | Associativité |
|---|---|---|
a[i] a() af | Index, appel, accès terrain | de gauche à droite | !a -a | Négation unaire | de droite à gauche |
a/ba%ba*b | Opérateurs multiplicatifs | de gauche à droite |
a+b ab | Opérateurs additifs | de gauche à droite |
a>ba>=ba | Opérateurs relationnels | de gauche à droite |
a in b | Existence dans une liste ou une carte | de gauche à droite |
a is type | Comparaison de types, où type peut être bool, int, float, number, string, list, map, timestamp, duration, path ou latlng | de gauche à droite |
a==ba!=b | Opérateurs de comparaison | de gauche à droite | a && b | ET conditionnel | de gauche à droite |
a || b | OU conditionnel | de gauche à droite |
a ? true_value : false_value | Expression ternaire | de gauche à droite |
Base de données en temps réel
Une condition est une expression booléenne qui détermine si une opération particulière doit être autorisée ou refusée. Vous pouvez définir ces conditions dans les règles de base de données en temps réel des manières suivantes.
Variables prédéfinies
Il existe un certain nombre de variables prédéfinies utiles accessibles dans une définition de règle. Voici un bref résumé de chacun :
| Variables prédéfinies | |
|---|---|
| maintenant | L'heure actuelle en millisecondes depuis l'époque Linux. Cela fonctionne particulièrement bien pour valider les horodatages créés avec firebase.database.ServerValue.TIMESTAMP du SDK. |
| racine | Un RuleDataSnapshot représentant le chemin racine dans la base de données Firebase tel qu'il existe avant la tentative d'opération. |
| nouvelles données | Un RuleDataSnapshot représentant les données telles qu'elles existeraient après la tentative d'opération. Il comprend les nouvelles données en cours d'écriture et les données existantes. |
| données | Un RuleDataSnapshot représentant les données telles qu'elles existaient avant la tentative d'opération. |
| variables $ | Un chemin générique utilisé pour représenter les identifiants et les clés enfants dynamiques. |
| authentification | Représente la charge utile du jeton d'un utilisateur authentifié. |
Ces variables peuvent être utilisées n'importe où dans vos règles. Par exemple, les règles de sécurité ci-dessous garantissent que les données écrites sur le nœud /foo/ doivent être une chaîne de moins de 100 caractères :
{
"rules": {
"foo": {
// /foo is readable by the world
".read": true,
// /foo is writable by the world
".write": true,
// data written to /foo must be a string less than 100 characters
".validate": "newData.isString() && newData.val().length < 100"
}
}
}
Règles basées sur les données
Toutes les données de votre base de données peuvent être utilisées dans vos règles. À l'aide des variables prédéfinies root , data et newData , vous pouvez accéder à n'importe quel chemin tel qu'il existerait avant ou après un événement d'écriture.
Prenons cet exemple, qui autorise les opérations d'écriture tant que la valeur du nœud /allow_writes/ est true , que le nœud parent n'a pas d'indicateur readOnly défini et qu'il y a un enfant nommé foo dans les données nouvellement écrites :
".write": "root.child('allow_writes').val() === true &&
!data.parent().child('readOnly').exists() &&
newData.child('foo').exists()"
Règles basées sur des requêtes
Bien que vous ne puissiez pas utiliser de règles comme filtres, vous pouvez limiter l'accès à des sous-ensembles de données en utilisant des paramètres de requête dans vos règles. Utilisez query. expressions dans vos règles pour accorder un accès en lecture ou en écriture en fonction des paramètres de requête.
Par exemple, la règle basée sur une requête suivante utilise des règles de sécurité basées sur l'utilisateur et des règles basées sur des requêtes pour restreindre l'accès aux données de la collection de baskets aux seuls paniers appartenant à l'utilisateur actif :
"baskets": {
".read": "auth.uid !== null &&
query.orderByChild === 'owner' &&
query.equalTo === auth.uid" // restrict basket access to owner of basket
}
La requête suivante, qui inclut les paramètres de requête dans la règle, réussirait :
db.ref("baskets").orderByChild("owner")
.equalTo(auth.currentUser.uid)
.on("value", cb) // Would succeed
Cependant, les requêtes qui n'incluent pas les paramètres dans la règle échoueront avec une erreur PermissionDenied :
db.ref("baskets").on("value", cb) // Would fail with PermissionDenied
Vous pouvez également utiliser des règles basées sur des requêtes pour limiter la quantité de données téléchargées par un client via des opérations de lecture.
Par exemple, la règle suivante limite l'accès en lecture aux 1 000 premiers résultats d'une requête, classés par priorité :
messages: {
".read": "query.orderByKey &&
query.limitToFirst <= 1000"
}
// Example queries:
db.ref("messages").on("value", cb) // Would fail with PermissionDenied
db.ref("messages").limitToFirst(1000)
.on("value", cb) // Would succeed (default order by key)
La query. les expressions sont disponibles dans les règles de sécurité de la base de données en temps réel.
| Expressions de règles basées sur des requêtes | ||
|---|---|---|
| Expression | Taper | Description |
| requête.orderByKey requête.orderByPriority requête.orderByValue | booléen | True pour les requêtes classées par clé, priorité ou valeur. Faux sinon. |
| requête.orderByChild | chaîne nul | Utilisez une chaîne pour représenter le chemin relatif vers un nœud enfant. Par exemple, query.orderByChild === "address/zip" . Si la requête n'est pas ordonnée par un nœud enfant, cette valeur est nulle. |
| requête.startAt requête.endAt requête.equalTo | chaîne nombre booléen nul | Récupère les limites de la requête en cours d'exécution ou renvoie null s'il n'y a pas d'ensemble lié. |
| requête.limitToFirst requête.limitToLast | nombre nul | Récupère la limite de la requête en cours d'exécution ou renvoie null si aucune limite n'est définie. |
Les opérateurs
Les règles de base de données en temps réel prennent en charge un certain nombre d' opérateurs que vous pouvez utiliser pour combiner des variables dans l'instruction de condition. Consultez la liste complète des opérateurs dans la documentation de référence .
Créer des conditions
Vos conditions réelles varieront en fonction de l’accès que vous souhaitez accorder. Les règles offrent intentionnellement un énorme degré de flexibilité, de sorte que les règles de votre application peuvent en fin de compte être aussi simples ou aussi complexes que vous le souhaitez.
Pour obtenir des conseils sur la création de règles simples prêtes pour la production, consultez Règles de sécurité de base .