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 aussi générales que nécessaire 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 Common Expression Language (CEL) , qui s'appuie sur CEL avec des déclarations de match et 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 créez les règles :

  • Request : 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 de read et d' 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 créez les règles :

  • Request : 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 de read et d' 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 consistent en des 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.
  • Demande : il s'agit des méthodes utilisées par la règle pour accorder l'accès. Les règles de read et d' write accordent un large accès en lecture et en écriture, tandis que les règles de validate agissent comme une vérification secondaire pour accorder l'accès en fonction des données entrantes ou existantes.
  • Condition : la condition qui autorise une demande 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 de 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 d'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 de function facultatives : offrent la possibilité de combiner et d'encapsuler des conditions à utiliser dans plusieurs règles.

Le service contient un ou plusieurs blocs de match avec des instructions allow qui fournissent des conditions accordant l'accès aux demandes. Les variables de request et resource peuvent être utilisées dans les conditions de règle. Le langage Firebase Security Rules prend également en charge les déclarations de function .

Version de syntaxe

La déclaration de syntax indique la version du langage Firebase Rules utilisée pour écrire la source. La dernière version du langage est la 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 de 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 la CLI Firebase, vous devrez les conserver dans des fichiers séparés.

Match

Un bloc de match déclare un modèle de path qui est mis en correspondance avec le chemin de l'opération demandée (le request.path entrant). Le corps de la match doit avoir un ou plusieurs blocs de match imbriqués, des instructions allow ou des déclarations de function . Le chemin dans les blocs de match imbriqués est relatif au chemin dans le bloc de match parent.

Le modèle de path est un nom de type répertoire qui peut inclure des variables ou des caractères génériques. Le modèle de path permet des correspondances de segments à chemin unique et de segments à chemins multiples. Toutes les variables liées dans un path sont visibles dans la portée de match ou dans toute portée imbriquée où le path est déclaré.

Les correspondances avec un modèle de path peuvent être partielles ou complètes :

  • Correspondances partielles : le modèle de path est une correspondance de préfixe de request.path .
  • Correspondances complètes : le modèle de path correspond à l'intégralité de 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 de 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 faut autoriser la demande. Si une règle correspondante accorde l'accès, la demande est autorisée. Si aucune règle correspondante 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 de 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 en tant que string .
  • Caractère générique récursif : le caractère générique récursif ou multisegment 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 règles réelles. Vous pouvez appliquer des règles d' 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 accorde toute demande entrante. Vous pouvez également écrire des instructions allow sans conditions, par exemple, allow read . Cependant, 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 d' 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 toutes les règles plus granulaires qui pourraient limiter l'accès.

Prenons l'exemple suivant, où 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 qui demande l'écriture est propriétaire du fichier et que le fichier est un 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 de commodité
read Tout type de demande de lecture
write Tout type de demande d'écriture
Méthodes standards
get Lire les demandes de documents ou de fichiers uniques
list Lire les requêtes pour les requêtes et les collections
create Rédiger 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 des méthodes de lecture dans le même bloc de match ou des méthodes d'écriture en conflit dans la même déclaration de 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

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 ne peuvent contenir qu'une seule instruction de return . Ils ne peuvent contenir aucune 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 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 de resource et aux fonctions intégrées telles que get() et exists() .
  • Les fonctions peuvent appeler d'autres fonctions mais ne peuvent pas être récursives. 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 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();
    }
  }
}

Voici un exemple montrant les arguments de fonction et les affectations 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 de la collection admins. Pour une évaluation paresseuse sans nécessiter de recherches inutiles, profitez de la nature de court-circuit de && (AND) et || (OR) pour appeler une deuxième fonction uniquement si isAuthor est 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 maintenables à 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 de 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 d'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 de function facultatives : offrent la possibilité de combiner et d'encapsuler des conditions à utiliser dans plusieurs règles.

Le service contient un ou plusieurs blocs de match avec des instructions allow qui fournissent des conditions accordant l'accès aux demandes. Les variables de request et resource peuvent être utilisées dans les conditions de règle. Le langage Firebase Security Rules prend également en charge les déclarations de function .

Version de syntaxe

La déclaration de syntax indique la version du langage Firebase Rules utilisée pour écrire la source. La dernière version du langage est la 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 de 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 la CLI Firebase, vous devrez les conserver dans des fichiers séparés.

Match

Un bloc de match déclare un modèle de path qui est mis en correspondance avec le chemin de l'opération demandée (le request.path entrant). Le corps de la match doit avoir un ou plusieurs blocs de match imbriqués, des instructions allow ou des déclarations de function . Le chemin dans les blocs de match imbriqués est relatif au chemin dans le bloc de match parent.

Le modèle de path est un nom de type répertoire qui peut inclure des variables ou des caractères génériques. Le modèle de path permet des correspondances de segments à chemin unique et de segments à chemins multiples. Toutes les variables liées dans un path sont visibles dans la portée de match ou dans toute portée imbriquée où le path est déclaré.

Les correspondances avec un modèle de path peuvent être partielles ou complètes :

  • Correspondances partielles : le modèle de path est une correspondance de préfixe de request.path .
  • Correspondances complètes : le modèle de path correspond à l'intégralité de 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 de 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 faut autoriser la demande. Si une règle correspondante accorde l'accès, la demande est autorisée. Si aucune règle correspondante 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 de 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 en tant que string .
  • Caractère générique récursif : le caractère générique récursif ou multisegment 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 règles réelles. Vous pouvez appliquer des règles d' 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 accorde toute demande entrante. Vous pouvez également écrire des instructions allow sans conditions, par exemple, allow read . Cependant, 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 d' 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 toutes les règles plus granulaires qui pourraient limiter l'accès.

Prenons l'exemple suivant, où 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 qui demande l'écriture est propriétaire du fichier et que le fichier est un 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 de commodité
read Tout type de demande de lecture
write Tout type de demande d'écriture
Méthodes standards
get Lire les demandes de documents ou de fichiers uniques
list Lire les requêtes pour les requêtes et les collections
create Rédiger 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 des méthodes de lecture dans le même bloc de match ou des méthodes d'écriture en conflit dans la même déclaration de 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

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 ne peuvent contenir qu'une seule instruction de return . Ils ne peuvent contenir aucune 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 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 de resource et aux fonctions intégrées telles que get() et exists() .
  • Les fonctions peuvent appeler d'autres fonctions mais ne peuvent pas être récursives. 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 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();
    }
  }
}

Voici un exemple montrant les arguments de fonction et les affectations 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 de la collection admins. Pour une évaluation paresseuse sans nécessiter de recherches inutiles, profitez de la nature de court-circuit de && (AND) et || (OR) pour appeler une deuxième fonction uniquement si isAuthor est 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 maintenables à 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 incluent 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 pouvez avoir des données qui ressemblent à 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 demande entrante. Le type de règle de 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ègle
.lis Décrit si et quand les données sont autorisées à être lues par les utilisateurs.
.écrivez Décrit si et quand les données sont autorisées à être écrites.
.valider Définit à quoi ressemblera une valeur correctement formatée, si elle a des attributs enfants et le type de données.

Par défaut, si aucune règle ne l'autorise, 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 de request et resource fournissent un contexte pour ces conditions.

La variable de request

La variable de request comprend les champs suivants et les informations correspondantes :

request.auth

Un jeton Web JSON (JWT) contenant les identifiants d'authentification de Firebase Authentication. auth token contient un ensemble de revendications standard et toutes les revendications personnalisées que vous créez via Firebase Authentication. En savoir plus sur les règles de sécurité et l'authentification Firebase .

request.method

La méthode request.method peut être l'une des méthodes standard ou une méthode personnalisée. Les méthodes de commodité 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 en écriture seule.

request.params

Les request.params incluent toutes les données non spécifiquement liées à la 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 autres que des 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 dans le service représentée sous la forme d'une carte de paires clé-valeur. Le référencement d'une resource dans une condition entraînera au plus une lecture de la valeur à partir du service. Cette recherche sera prise en compte dans tout quota lié au service pour la ressource. Pour les demandes d' get , la resource ne sera comptabilisée 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 indice i .

Opérateur La 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 la liste ou la carte de gauche à droite
a is type Comparaison de type, 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 de request et resource fournissent un contexte pour ces conditions.

La variable de request

La variable de request comprend les champs suivants et les informations correspondantes :

request.auth

Un jeton Web JSON (JWT) contenant les identifiants d'authentification de Firebase Authentication. auth token contient un ensemble de revendications standard et toutes les revendications personnalisées que vous créez via Firebase Authentication. En savoir plus sur les règles de sécurité et l'authentification Firebase .

request.method

La méthode request.method peut être l'une des méthodes standard ou une méthode personnalisée. Les méthodes de commodité 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 en écriture seule.

request.params

Les request.params incluent toutes les données non spécifiquement liées à la 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 autres que des 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 dans le service représentée sous la forme d'une carte de paires clé-valeur. Le référencement d'une resource dans une condition entraînera au plus une lecture de la valeur à partir du service. Cette recherche sera prise en compte dans tout quota lié au service pour la ressource. Pour les demandes d' get , la resource ne sera comptabilisée 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 indice i .

Opérateur La 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 la liste ou la carte de gauche à droite
a is type Comparaison de type, 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

Un certain nombre de variables prédéfinies utiles sont accessibles dans une définition de règle. Voici un bref résumé de chacun :

Variables prédéfinies
à présent 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 l'opération tentée.
nouvelles données Un RuleDataSnapshot représentant les données telles qu'elles existeraient après l'opération tentée. Il comprend les nouvelles données en cours d'écriture et les données existantes.
Les données Un RuleDataSnapshot représentant les données telles qu'elles existaient avant l'opération tentée.
variable $ 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. En utilisant les 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.

Considérez 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 existe 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 les 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 les requêtes suivante utilise des règles de sécurité basées sur l'utilisateur et des règles basées sur les requêtes pour limiter l'accès aux données de la collection de baskets aux seuls paniers que l'utilisateur actif possède :

"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 échoueraient 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 qu'un client télécharge via des opérations de lecture.

Par exemple, la règle suivante limite l'accès en lecture aux seuls 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 base de données en temps réel.

Expressions de règles basées sur des requêtes
Expression Taper La description
query.orderByKey
query.orderByPriority
query.orderByValue
booléen True pour les requêtes classées par clé, priorité ou valeur. Faux sinon.
query.orderByChild chaîne de caractères
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.
query.startAt
query.endAt
query.equalTo
chaîne de caractères
Numéro
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 de limites.
query.limitToFirst
query.limitToLast
Numéro
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. Voir 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 degré énorme de flexibilité, de sorte que les règles de votre application peuvent finalement être aussi simples ou aussi complexes que vous en avez besoin.

Pour obtenir des conseils sur la création de règles simples et prêtes pour la production, consultez Règles de sécurité de base .