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
etdelete
. Les méthodes pratiquesread
etwrite
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
etdelete
. Les méthodes pratiquesread
etwrite
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
etwrite
accordent un large accès en lecture et en écriture, tandis que les règlesvalidate
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 pratiquesread
etwrite
. - 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 derequest.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'instructionmatch
sous 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'instructionmatch
en 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.firestore
a accès à la variableresource
et 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
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 pratiquesread
etwrite
. - 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 derequest.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'instructionmatch
sous 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'instructionmatch
en 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.firestore
a accès à la variableresource
et 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
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 .