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

Apprenez la syntaxe de base du langage Realtime Database Rules

Les règles de sécurité de la base de données en temps réel Firebase vous permettent de contrôler l'accès aux données stockées dans votre base de données. La syntaxe flexible des règles vous permet de créer des règles qui correspondent à tout, de toutes les écritures dans votre base de données aux opérations sur des nœuds individuels.

Base de données en temps réel les règles de sécurité sont la configuration déclarative pour votre base de données. Cela signifie que les règles sont définies séparément de la logique du produit. Cela présente un certain nombre d'avantages : les clients ne sont pas responsables de l'application de la sécurité, les implémentations boguées ne compromettront pas vos données, et peut-être plus important encore, il n'y a pas besoin d'un arbitre intermédiaire, tel qu'un serveur, pour protéger les données du monde.

Cette rubrique décrit la syntaxe et la structure de base des règles de sécurité de base de données en temps réel utilisées pour créer des ensembles de règles complets.

Structurer vos règles de sécurité

Les règles de sécurité de base de données en temps réel sont constituées d'expressions de type JavaScript contenues dans un document JSON. La structure de vos règles doit suivre la structure des données que vous avez stockées dans votre base de données.

Règles de base identifient un ensemble de noeuds à sécuriser, les méthodes d'accès (par exemple, lecture, écriture) participe et les conditions dans lesquelles l' accès est soit autorisé ou refusé. Dans les exemples qui suivent, nos conditions seront simples true et false déclarations, mais dans le sujet suivant nous allons couvrir plus de moyens dynamiques pour exprimer des conditions.

Ainsi, par exemple, si nous essayons d'obtenir un child_node sous parent_node , la syntaxe générale à suivre est le suivant :

{
  "rules": {
    "parent_node": {
      "child_node": {
        ".read": <condition>,
        ".write": <condition>,
        ".validate": <condition>,
      }
    }
  }
}

Appliquons ce modèle. Par exemple, disons que vous gardez une trace d'une liste de messages et que vous avez des données qui ressemblent à ceci :

{
  "messages": {
    "message0": {
      "content": "Hello",
      "timestamp": 1405704370369
    },
    "message1": {
      "content": "Goodbye",
      "timestamp": 1405704395231
    },
    ...
  }
}

Vos règles doivent être structurées de la même manière. Voici un ensemble de règles de sécurité en lecture seule qui pourraient avoir un sens pour cette structure de données. Cet exemple illustre comment nous spécifions les nœuds de base de données auxquels les règles s'appliquent et les conditions d'évaluation des règles sur ces nœuds.

{
  "rules": {
    // For requests to access the 'messages' node...
    "messages": {
      // ...and the individual wildcarded 'message' nodes beneath
      // (we'll cover wildcarding variables more a bit later)....
      "$message": {

        // For each message, allow a read operation if <condition>. In this
        // case, we specify our condition as "true", so read access is always granted.
        ".read": "true",

        // For read-only behavior, we specify that for write operations, our
        // condition is false.
        ".write": "false"
      }
    }
  }
}

Règles de base Opérations

Il existe trois types de règles pour faire respecter la sécurité en fonction du type d'opération effectuée sur les données: .write , .read et .validate . Voici un bref résumé de leurs objectifs :

Types de règles
.lire 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.

Variables de capture génériques

Toutes les instructions de règles pointent vers des nœuds. Une déclaration peut pointer vers un noeud spécifique ou utilisez $ les variables de capture génériques pour pointer vers des ensembles de nœuds à un niveau de la hiérarchie. Utilisez ces variables de capture pour stocker la valeur des clés de nœud à utiliser dans les instructions de règles suivantes. Cette technique vous permet d' écrire des conditions de règles plus complexes, quelque chose que nous allons aborder plus en détail dans le sujet suivant.

{
  "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')"
        }
      }
    }
  }
}

La dynamique $ variables peuvent également être utilisés en parallèle avec des noms de chemin constant. Dans cet exemple, nous utilisons l' $other variable pour déclarer une .validate règle qui garantit que widget de n'a pas d' enfant autre que le title et la color . Toute écriture qui entraînerait la création d'enfants supplémentaires échouerait.

{
  "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 }
    }
  }
}

Cascade de règles de lecture et d'écriture

.read et .write règles fonctionnent de haut en bas, avec des règles moins profondes prépondérants des règles plus profondes. Si une subvention de la règle de lecture ou d' autorisations d'écriture sur un chemin particulier, il accorde également accès à tous les nœuds enfants en dessous. Considérez la structure suivante :

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}

Cette structure de sécurité permet /bar/ à lire à partir de chaque fois /foo/ contient un enfant baz avec la valeur true . Le ".read": false règle sous /foo/bar/ n'a pas d' effet ici, puisque l' accès ne peut être révoqué par un chemin d'enfant.

Bien que cela ne semble pas immédiatement intuitif, il s'agit d'une partie puissante du langage de règles et permet de mettre en œuvre des privilèges d'accès très complexes avec un effort minimal. Cela sera illustré lorsque nous aborderons la sécurité basée sur l'utilisateur plus loin dans ce guide.

Notez que .validate règles ne sont pas en cascade. Toutes les règles de validation doivent être satisfaites à tous les niveaux de la hiérarchie pour qu'une écriture soit autorisée.

Les règles ne sont pas des filtres

Les règles sont appliquées de manière atomique. Cela signifie qu'une opération de lecture ou d'écriture échoue immédiatement s'il n'y a pas de règle à cet emplacement ou à un emplacement parent qui accorde l'accès. Même si chaque chemin enfant affecté est accessible, la lecture à l'emplacement parent échouera complètement. Considérez cette structure :

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Sans comprendre que les règles sont évaluées atomiquement, il peut sembler aller chercher le /records/ chemin retournerait rec1 mais pas rec2 . Le résultat réel, cependant, est une erreur :

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objectif c
Note: Ce produit Firebase n'est pas disponible sur la cible Clip App.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Rapide
Note: Ce produit Firebase n'est pas disponible sur la cible Clip App.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
DU REPOS
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Depuis l'opération de lecture à /records/ est atomique, et il n'y a pas de règle de lecture qui donne accès à toutes les données sous /records/ , cela lancera une PERMISSION_DENIED erreur. Si nous évaluons cette règle dans le simulateur de sécurité dans notre console Firebase , nous pouvons voir que l'opération de lecture a été refusée car aucune règle de lecture a permis l' accès au /records/ chemin. Toutefois, notez que la règle de rec1 n'a jamais été évaluée parce qu'il n'a pas été dans le chemin que nous avons demandé. Pour chercher rec1 , nous aurions besoin d'y accéder directement:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objectif c
Note: Ce produit Firebase n'est pas disponible sur la cible Clip App.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Rapide
Note: Ce produit Firebase n'est pas disponible sur la cible Clip App.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
DU REPOS
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Chevauchement des déclarations

Il est possible que plusieurs règles s'appliquent à un nœud. Dans le cas où plusieurs expressions règles identifient un noeud, la méthode d'accès est refusée si l' une des conditions est false :

{
  "rules": {
    "messages": {
      // A rule expression that applies to all nodes in the 'messages' node
      "$message": {
        ".read": "true",
        ".write": "true"
      },
      // A second rule expression applying specifically to the 'message1` node
      "message1": {
        ".read": "false",
        ".write": "false"
      }
    }
  }
}

Dans l'exemple ci - dessus, lit au message1 nœud sera refusée parce que les secondes règles est toujours false , même si la première règle est toujours true .

Prochaines étapes

Vous pouvez approfondir votre compréhension des règles de sécurité de la base de données en temps réel Firebase :

  • Apprendre le prochain concept majeur de la langue règles, dynamiques conditions , qui laissez votre autorisation utilisateur vérifier les règles, comparer les données existantes et entrantes, valider les données entrantes, vérifier la structure des requêtes provenant du client, et plus encore.

  • Passez en revue les cas d'utilisation typiques de la sécurité et les définitions Règles de sécurité Firebase cette adresse leur .