Langage des règles de sécurité

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 , update et delete . Les méthodes pratiques read et write permettent 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 , update et delete . Les méthodes pratiques read et write permettent 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 read et write accordent un large accès en lecture et en écriture, tandis que les règles validate agissent 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 , delete et les méthodes pratiques read et write .
  • Déclarations function facultatives : 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 path est une correspondance de préfixe de request.path .
  • Correspondances complètes : le modèle path correspond à 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'instruction match sous forme de string .
  • 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'instruction match en tant qu'objet path .

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.firestore a accès à la variable resource et aux fonctions intégrées telles que get() et exists() .
  • 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 v2 des 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 , delete et les méthodes pratiques read et write .
  • Déclarations function facultatives : 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 path est une correspondance de préfixe de request.path .
  • Correspondances complètes : le modèle path correspond à 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'instruction match sous forme de string .
  • 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'instruction match en tant qu'objet path .

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.firestore a accès à la variable resource et aux fonctions intégrées telles que get() et exists() .
  • 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 v2 des 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 .