Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Sprache der Sicherheitsregeln

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

Firebase-Sicherheitsregeln nutzen flexible, leistungsstarke, benutzerdefinierte Sprachen, die ein breites Spektrum an Komplexität und Granularität unterstützen. Sie können Ihre Regeln so spezifisch oder allgemein gestalten, wie es für Ihre App sinnvoll ist. Echtzeitdatenbankregeln verwenden eine Syntax, die wie JavaScript in einer JSON-Struktur aussieht. Cloud Firestore- und Cloud Storage-Regeln verwenden eine Sprache, die auf der Common Expression Language (CEL) basiert, die auf CEL mit match und allow -Anweisungen aufbaut, die bedingt gewährten Zugriff unterstützen.

Da es sich jedoch um benutzerdefinierte Sprachen handelt, gibt es eine Lernkurve. Verwenden Sie diesen Leitfaden, um die Sprache der Regeln besser zu verstehen, während Sie tiefer in komplexere Regeln eintauchen.

Wählen Sie ein Produkt aus, um mehr über seine Regeln zu erfahren.

Grundstruktur

Cloud-Firestore

Firebase-Sicherheitsregeln in Cloud Firestore und Cloud Storage verwenden die folgende Struktur und Syntax:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Die folgenden Schlüsselkonzepte müssen beim Erstellen der Regeln unbedingt verstanden werden:

  • Anfrage: Die Methode oder Methoden, die in der allow Anweisung aufgerufen werden. Dies sind Methoden, die Sie ausführen lassen. Die Standardmethoden sind: get , list , create , update und delete . Die bequemen read und Schreibmethoden ermöglichen einen breiten Lese- und write auf die angegebene Datenbank oder den angegebenen Speicherpfad.
  • Pfad: Die Datenbank oder der Speicherort, dargestellt als URI-Pfad.
  • Regel: Die allow Anweisung, die eine Bedingung enthält, die eine Anfrage zulässt, wenn sie als wahr ausgewertet wird.

Jedes dieser Konzepte wird nachstehend ausführlicher beschrieben.

Cloud-Speicher

Firebase-Sicherheitsregeln in Cloud Firestore und Cloud Storage verwenden die folgende Struktur und Syntax:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Die folgenden Schlüsselkonzepte müssen beim Erstellen der Regeln unbedingt verstanden werden:

  • Anfrage: Die Methode oder Methoden, die in der allow Anweisung aufgerufen werden. Dies sind Methoden, die Sie ausführen lassen. Die Standardmethoden sind: get , list , create , update und delete . Die bequemen read und Schreibmethoden ermöglichen einen breiten Lese- und write auf die angegebene Datenbank oder den angegebenen Speicherpfad.
  • Pfad: Die Datenbank oder der Speicherort, dargestellt als URI-Pfad.
  • Regel: Die allow Anweisung, die eine Bedingung enthält, die eine Anfrage zulässt, wenn sie als wahr ausgewertet wird.

Jedes dieser Konzepte wird nachstehend ausführlicher beschrieben.

Echtzeit-Datenbank

In Realtime Database bestehen Firebase-Sicherheitsregeln aus JavaScript-ähnlichen Ausdrücken, die in einem JSON-Dokument enthalten sind.

Sie verwenden die folgende Syntax:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

Es gibt drei grundlegende Elemente in der Regel:

  • Pfad: Der Datenbankspeicherort. Dies spiegelt die JSON-Struktur Ihrer Datenbank wider.
  • Anfrage: Dies sind die Methoden, die die Regel verwendet, um Zugriff zu gewähren. Die read und write gewähren breiten Lese- und Schreibzugriff, während validate als sekundäre Überprüfung dienen, um Zugriff basierend auf eingehenden oder vorhandenen Daten zu gewähren.
  • Bedingung: Die Bedingung, die eine Anfrage zulässt, wenn sie als wahr ausgewertet wird.

Regelkonstrukte

Cloud-Firestore

Die grundlegenden Elemente einer Regel in Cloud Firestore und Cloud Storage sind wie folgt:

  • Die service : Deklariert das Firebase-Produkt, für das die Regeln gelten.
  • Der match : Definiert einen Pfad in der Datenbank oder im Speicher-Bucket, für den die Regeln gelten.
  • Die allow -Anweisung: Stellt Bedingungen für die Gewährung des Zugriffs bereit, differenziert nach Methoden. Zu den unterstützten Methoden gehören: get , list , create , update , delete und die praktischen Methoden read und write .
  • Optionale function : Bieten die Möglichkeit, Bedingungen für die Verwendung über mehrere Regeln hinweg zu kombinieren und zu umschließen.

Der service enthält einen oder mehrere match -Blöcke mit allow -Anweisungen, die Bedingungen bereitstellen, die Zugriff auf Anforderungen gewähren. Die request und resource stehen zur Verwendung in Regelbedingungen zur Verfügung. Die Sprache der Firebase-Sicherheitsregeln unterstützt auch function .

Syntaxversion

Die syntax gibt die Version der Firebase-Regelsprache an, die zum Schreiben der Quelle verwendet wurde. Die neueste Version der Sprache ist v2 .

rules_version = '2';
service cloud.firestore {
...
}

Wenn keine rules_version Anweisung angegeben wird, werden Ihre Regeln mit der v1 -Engine ausgewertet.

Service

Die service definiert, für welches Firebase-Produkt oder -Dienst Ihre Regeln gelten. Sie können nur eine service Deklaration pro Quelldatei einschließen.

Cloud-Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud-Speicher

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Wenn Sie Regeln sowohl für Cloud Firestore als auch für Cloud Storage mit der Firebase-Befehlszeilenschnittstelle definieren, müssen Sie sie in separaten Dateien verwalten.

Passen

Ein match deklariert ein path , das mit dem Pfad für die angeforderte Operation (dem eingehenden request.path ) abgeglichen wird. Der Hauptteil der match muss einen oder mehrere verschachtelte match , allow Anweisungen oder function enthalten. Der Pfad in verschachtelten match ist relativ zum Pfad im übergeordneten match .

Das path ist ein verzeichnisähnlicher Name, der Variablen oder Platzhalter enthalten kann. Das path ermöglicht Einzelpfadsegment- und Mehrpfadsegmentübereinstimmungen. Alle in einem path gebundenen Variablen sind innerhalb des match oder eines beliebigen verschachtelten Bereichs sichtbar, in dem der path deklariert ist.

Übereinstimmungen mit einem path können teilweise oder vollständig sein:

  • Teilübereinstimmungen : Das path ist eine Präfixübereinstimmung von request.path .
  • Vollständige Übereinstimmungen: Das path stimmt mit dem gesamten request.path .

Wenn eine vollständige Übereinstimmung besteht, werden die Regeln innerhalb des Blocks ausgewertet. Wenn eine teilweise Übereinstimmung erfolgt, werden die verschachtelten match getestet, um zu sehen, ob irgendein verschachtelter path die Übereinstimmung vervollständigt .

Die Regeln in jeder vollständigen match werden ausgewertet, um zu bestimmen, ob die Anforderung zugelassen wird. Wenn eine übereinstimmende Regel Zugriff gewährt, wird die Anfrage zugelassen. Wenn keine übereinstimmende Regel Zugriff gewährt, wird die Anfrage abgelehnt.

// 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.
  }
}

Wie das obige Beispiel zeigt, unterstützt die path die folgenden Variablen:

  • Einzelsegment-Wildcard: Eine Wildcard-Variable wird in einem Pfad deklariert, indem eine Variable in geschweifte Klammern eingeschlossen wird: {variable} . Auf diese Variable kann innerhalb der match - Anweisung als string werden .
  • Rekursiver Platzhalter: Der rekursive oder mehrteilige Platzhalter stimmt mit mehreren Pfadsegmenten auf oder unter einem Pfad überein. Dieser Platzhalter stimmt mit allen Pfaden unterhalb des Speicherorts überein, auf den Sie ihn festgelegt haben. Sie können es deklarieren, indem Sie die Zeichenfolge =** am Ende Ihrer Segmentvariablen hinzufügen: {variable=**} . Auf diese Variable kann innerhalb der match -Anweisung als path zugegriffen werden.

Erlauben

Der match -Block enthält eine oder mehrere allow -Anweisungen. Dies sind Ihre eigentlichen Regeln. Sie können Zulassungsregeln auf allow oder mehrere Methoden anwenden. Die Bedingungen in einer allow -Anweisung müssen als „true“ ausgewertet werden, damit Cloud Firestore oder Cloud Storage jede eingehende Anfrage gewähren kann. Sie können auch Allow-Anweisungen ohne Bedingungen schreiben, zum Beispiel allow allow read . Wenn die allow Anweisung jedoch keine Bedingung enthält, lässt sie die Anfrage für diese Methode immer zu.

Wenn allow der Zulassungsregeln für die Methode erfüllt ist, wird die Anforderung zugelassen. Wenn darüber hinaus eine umfassendere Regel Zugriff gewährt, gewährt Rules Zugriff und ignoriert alle detaillierteren Regeln, die den Zugriff einschränken könnten.

Betrachten Sie das folgende Beispiel, in dem jeder Benutzer seine eigenen Dateien lesen oder löschen kann. Eine detailliertere Regel lässt Schreibvorgänge nur zu, wenn der Benutzer, der den Schreibvorgang anfordert, Eigentümer der Datei ist und die Datei ein PNG ist. Ein Benutzer kann alle Dateien im Unterpfad löschen – auch wenn es sich nicht um PNGs handelt – da die frühere Regel dies zulässt.

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');
  }
}

Methode

Jede allow Anweisung enthält eine Methode, die eingehenden Anforderungen derselben Methode Zugriff gewährt.

Methode Art der Anfrage
Convenience-Methoden
read Jede Art von Leseanforderung
write Jede Art von Schreibanforderung
Standardmethoden
get Leseanfragen für einzelne Dokumente oder Dateien
list Leseanforderungen für Abfragen und Sammlungen
create Schreiben Sie neue Dokumente oder Dateien
update Schreiben Sie in vorhandene Datenbankdokumente oder aktualisieren Sie Dateimetadaten
delete Daten löschen

Sie können Lesemethoden im selben match oder widersprüchliche Schreibmethoden in derselben path nicht überlappen.

Beispielsweise würden die folgenden Regeln fehlschlagen:

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

Funktion

Wenn Ihre Sicherheitsregeln komplexer werden, möchten Sie möglicherweise Sätze von Bedingungen in Funktionen einschließen, die Sie in Ihrem Regelsatz wiederverwenden können. Sicherheitsregeln unterstützen benutzerdefinierte Funktionen. Die Syntax für benutzerdefinierte Funktionen ist ein bisschen wie JavaScript, aber Sicherheitsregelfunktionen sind in einer domänenspezifischen Sprache geschrieben, die einige wichtige Einschränkungen hat:

  • Funktionen können nur eine einzige return -Anweisung enthalten. Sie dürfen keine zusätzliche Logik enthalten. Sie können beispielsweise keine Schleifen ausführen oder externe Dienste aufrufen.
  • Funktionen können automatisch auf Funktionen und Variablen aus dem Gültigkeitsbereich zugreifen, in dem sie definiert sind. Beispielsweise hat eine im Bereich service cloud.firestore definierte Funktion Zugriff auf die resource und integrierte Funktionen wie get() undexists exists() .
  • Funktionen können andere Funktionen aufrufen, dürfen aber nicht rekursiv sein. Die gesamte Call-Stack-Tiefe ist auf 20 begrenzt.
  • In der Rules-Version v2 können Funktionen Variablen mit dem Schlüsselwort let definieren. Funktionen können bis zu 10 let-Bindungen haben, müssen aber mit einer return-Anweisung enden.

Eine Funktion wird mit dem Schlüsselwort function definiert und akzeptiert null oder mehr Argumente. Beispielsweise möchten Sie möglicherweise die beiden Arten von Bedingungen, die in den obigen Beispielen verwendet werden, in einer einzigen Funktion kombinieren:

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();
    }
  }
}

Hier ist ein Beispiel, das Funktionsargumente und let-Zuweisungen zeigt. Let-Zuweisungsanweisungen müssen durch Semikolons getrennt werden.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Beachten Sie, wie die isAdmin Zuweisung eine Suche nach der Admins-Sammlung erzwingt. Nutzen Sie für eine verzögerte Auswertung, ohne dass unnötige Nachschlagevorgänge erforderlich sind, die kurzschließende Natur von && (AND) und || (ODER)-Vergleiche, um eine zweite Funktion nur dann aufzurufen, wenn isAuthor als wahr (für && -Vergleiche) oder falsch (für || -Vergleiche) gezeigt wird.

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);
}

Die Verwendung von Funktionen in Ihren Sicherheitsregeln macht sie wartungsfreundlicher, wenn die Komplexität Ihrer Regeln zunimmt.

Cloud-Speicher

Die grundlegenden Elemente einer Regel in Cloud Firestore und Cloud Storage sind wie folgt:

  • Die service : Deklariert das Firebase-Produkt, für das die Regeln gelten.
  • Der match : Definiert einen Pfad in der Datenbank oder im Speicher-Bucket, für den die Regeln gelten.
  • Die allow -Anweisung: Stellt Bedingungen für die Gewährung des Zugriffs bereit, differenziert nach Methoden. Zu den unterstützten Methoden gehören: get , list , create , update , delete und die praktischen Methoden read und write .
  • Optionale function : Bieten die Möglichkeit, Bedingungen für die Verwendung über mehrere Regeln hinweg zu kombinieren und zu umschließen.

Der service enthält einen oder mehrere match -Blöcke mit allow -Anweisungen, die Bedingungen bereitstellen, die Zugriff auf Anforderungen gewähren. Die request und resource stehen zur Verwendung in Regelbedingungen zur Verfügung. Die Sprache der Firebase-Sicherheitsregeln unterstützt auch function .

Syntaxversion

Die syntax gibt die Version der Firebase-Regelsprache an, die zum Schreiben der Quelle verwendet wurde. Die neueste Version der Sprache ist v2 .

rules_version = '2';
service cloud.firestore {
...
}

Wenn keine rules_version Anweisung angegeben wird, werden Ihre Regeln mit der v1 -Engine ausgewertet.

Service

Die service definiert, für welches Firebase-Produkt oder -Dienst Ihre Regeln gelten. Sie können nur eine service Deklaration pro Quelldatei einschließen.

Cloud-Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud-Speicher

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Wenn Sie Regeln sowohl für Cloud Firestore als auch für Cloud Storage mit der Firebase-Befehlszeilenschnittstelle definieren, müssen Sie sie in separaten Dateien verwalten.

Passen

Ein match deklariert ein path , das mit dem Pfad für die angeforderte Operation (dem eingehenden request.path ) abgeglichen wird. Der Hauptteil der match muss einen oder mehrere verschachtelte match , allow Anweisungen oder function enthalten. Der Pfad in verschachtelten match ist relativ zum Pfad im übergeordneten match .

Das path ist ein verzeichnisähnlicher Name, der Variablen oder Platzhalter enthalten kann. Das path ermöglicht Einzelpfadsegment- und Mehrpfadsegmentübereinstimmungen. Alle in einem path gebundenen Variablen sind innerhalb des match oder eines beliebigen verschachtelten Bereichs sichtbar, in dem der path deklariert ist.

Übereinstimmungen mit einem path können teilweise oder vollständig sein:

  • Teilübereinstimmungen : Das path ist eine Präfixübereinstimmung von request.path .
  • Vollständige Übereinstimmungen: Das path stimmt mit dem gesamten request.path .

Wenn eine vollständige Übereinstimmung besteht, werden die Regeln innerhalb des Blocks ausgewertet. Wenn eine teilweise Übereinstimmung erfolgt, werden die verschachtelten match getestet, um zu sehen, ob irgendein verschachtelter path die Übereinstimmung vervollständigt .

Die Regeln in jeder vollständigen match werden ausgewertet, um zu bestimmen, ob die Anforderung zugelassen wird. Wenn eine übereinstimmende Regel Zugriff gewährt, wird die Anfrage zugelassen. Wenn keine übereinstimmende Regel Zugriff gewährt, wird die Anfrage abgelehnt.

// 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.
  }
}

Wie das obige Beispiel zeigt, unterstützt die path die folgenden Variablen:

  • Einzelsegment-Wildcard: Eine Wildcard-Variable wird in einem Pfad deklariert, indem eine Variable in geschweifte Klammern eingeschlossen wird: {variable} . Auf diese Variable kann innerhalb der match - Anweisung als string werden .
  • Rekursiver Platzhalter: Der rekursive oder mehrteilige Platzhalter stimmt mit mehreren Pfadsegmenten auf oder unter einem Pfad überein. Dieser Platzhalter stimmt mit allen Pfaden unterhalb des Speicherorts überein, auf den Sie ihn festgelegt haben. Sie können es deklarieren, indem Sie die Zeichenfolge =** am Ende Ihrer Segmentvariablen hinzufügen: {variable=**} . Auf diese Variable kann innerhalb der match -Anweisung als path zugegriffen werden.

Erlauben

Der match -Block enthält eine oder mehrere allow -Anweisungen. Dies sind Ihre eigentlichen Regeln. Sie können Zulassungsregeln auf allow oder mehrere Methoden anwenden. Die Bedingungen in einer allow -Anweisung müssen als „true“ ausgewertet werden, damit Cloud Firestore oder Cloud Storage jede eingehende Anfrage gewähren kann. Sie können auch Allow-Anweisungen ohne Bedingungen schreiben, zum Beispiel allow allow read . Wenn die allow Anweisung jedoch keine Bedingung enthält, lässt sie die Anfrage für diese Methode immer zu.

Wenn allow der Zulassungsregeln für die Methode erfüllt ist, wird die Anforderung zugelassen. Wenn darüber hinaus eine umfassendere Regel Zugriff gewährt, gewährt Rules Zugriff und ignoriert alle detaillierteren Regeln, die den Zugriff einschränken könnten.

Betrachten Sie das folgende Beispiel, in dem jeder Benutzer seine eigenen Dateien lesen oder löschen kann. Eine detailliertere Regel lässt Schreibvorgänge nur zu, wenn der Benutzer, der den Schreibvorgang anfordert, Eigentümer der Datei ist und die Datei ein PNG ist. Ein Benutzer kann alle Dateien im Unterpfad löschen – auch wenn es sich nicht um PNGs handelt – da die frühere Regel dies zulässt.

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');
  }
}

Methode

Jede allow Anweisung enthält eine Methode, die eingehenden Anforderungen derselben Methode Zugriff gewährt.

Methode Art der Anfrage
Convenience-Methoden
read Jede Art von Leseanforderung
write Jede Art von Schreibanforderung
Standardmethoden
get Leseanfragen für einzelne Dokumente oder Dateien
list Leseanforderungen für Abfragen und Sammlungen
create Schreiben Sie neue Dokumente oder Dateien
update Schreiben Sie in vorhandene Datenbankdokumente oder aktualisieren Sie Dateimetadaten
delete Daten löschen

Sie können Lesemethoden im selben match oder widersprüchliche Schreibmethoden in derselben path nicht überlappen.

Beispielsweise würden die folgenden Regeln fehlschlagen:

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

Funktion

Wenn Ihre Sicherheitsregeln komplexer werden, möchten Sie möglicherweise Sätze von Bedingungen in Funktionen einschließen, die Sie in Ihrem Regelsatz wiederverwenden können. Sicherheitsregeln unterstützen benutzerdefinierte Funktionen. Die Syntax für benutzerdefinierte Funktionen ist ein bisschen wie JavaScript, aber Sicherheitsregelfunktionen sind in einer domänenspezifischen Sprache geschrieben, die einige wichtige Einschränkungen hat:

  • Funktionen können nur eine einzige return -Anweisung enthalten. Sie dürfen keine zusätzliche Logik enthalten. Sie können beispielsweise keine Schleifen ausführen oder externe Dienste aufrufen.
  • Funktionen können automatisch auf Funktionen und Variablen aus dem Gültigkeitsbereich zugreifen, in dem sie definiert sind. Beispielsweise hat eine im Bereich service cloud.firestore definierte Funktion Zugriff auf die resource und integrierte Funktionen wie get() undexists exists() .
  • Funktionen können andere Funktionen aufrufen, dürfen aber nicht rekursiv sein. Die gesamte Call-Stack-Tiefe ist auf 20 begrenzt.
  • In der Rules-Version v2 können Funktionen Variablen mit dem Schlüsselwort let definieren. Funktionen können bis zu 10 let-Bindungen haben, müssen aber mit einer return-Anweisung enden.

Eine Funktion wird mit dem Schlüsselwort function definiert und akzeptiert null oder mehr Argumente. Beispielsweise möchten Sie möglicherweise die beiden Arten von Bedingungen, die in den obigen Beispielen verwendet werden, in einer einzigen Funktion kombinieren:

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();
    }
  }
}

Hier ist ein Beispiel, das Funktionsargumente und let-Zuweisungen zeigt. Let-Zuweisungsanweisungen müssen durch Semikolons getrennt werden.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Beachten Sie, wie die isAdmin Zuweisung eine Suche nach der Admins-Sammlung erzwingt. Nutzen Sie für eine verzögerte Auswertung, ohne dass unnötige Nachschlagevorgänge erforderlich sind, die kurzschließende Natur von && (AND) und || (ODER)-Vergleiche, um eine zweite Funktion nur dann aufzurufen, wenn isAuthor als wahr (für && -Vergleiche) oder falsch (für || -Vergleiche) gezeigt wird.

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);
}

Die Verwendung von Funktionen in Ihren Sicherheitsregeln macht sie wartungsfreundlicher, wenn die Komplexität Ihrer Regeln zunimmt.

Echtzeit-Datenbank

Wie oben beschrieben, umfassen Echtzeit-Datenbankregeln drei grundlegende Elemente: den Datenbankspeicherort als Spiegel der JSON-Struktur der Datenbank, den Anforderungstyp und die Zugriffsbedingung.

Speicherort der Datenbank

Die Struktur Ihrer Regeln sollte der Struktur der Daten folgen, die Sie in Ihrer Datenbank gespeichert haben. Beispielsweise haben Sie in einer Chat-App mit einer Liste von Nachrichten möglicherweise Daten, die wie folgt aussehen:

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

Ihre Regeln sollten diese Struktur widerspiegeln. Zum Beispiel:

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

Wie das obige Beispiel zeigt, unterstützen Echtzeit-Datenbankregeln eine $location Variable, um Pfadsegmente abzugleichen. Verwenden Sie das $ -Präfix vor Ihrem Pfadsegment, um Ihre Regel mit allen untergeordneten Knoten entlang des Pfads abzugleichen.

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

Sie können die $variable auch parallel mit konstanten Pfadnamen verwenden.

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

Methode

In Realtime Database gibt es drei Arten von Regeln. Zwei dieser Regeltypen – read und write – gelten für die Methode einer eingehenden Anfrage. Der validate erzwingt Datenstrukturen und validiert das Format und den Inhalt von Daten. Regeln führen .validate Regeln aus, nachdem überprüft wurde, ob eine .write Regel Zugriff gewährt.

Regeltypen
.lesen Beschreibt, ob und wann Daten von Benutzern gelesen werden dürfen.
.schreiben Beschreibt, ob und wann Daten geschrieben werden dürfen.
.bestätigen Definiert, wie ein korrekt formatierter Wert aussieht, ob er untergeordnete Attribute hat, und den Datentyp.

Wenn es keine Regel gibt, die dies zulässt, wird der Zugriff auf einen Pfad standardmäßig verweigert.

Bauliche Gegebenheiten

Cloud-Firestore

Eine Bedingung ist ein boolescher Ausdruck, der festlegt, ob eine bestimmte Operation zugelassen oder verweigert werden soll. Die request und resource stellen Kontext für diese Bedingungen bereit.

Die request

Die request enthält die folgenden Felder und entsprechende Informationen:

request.auth

Ein JSON Web Token (JWT), das Authentifizierungsdaten von Firebase Authentication enthält. auth enthält eine Reihe von Standardansprüchen und alle benutzerdefinierten Ansprüche, die Sie über die Firebase-Authentifizierung erstellen. Erfahren Sie mehr über Firebase-Sicherheitsregeln und -Authentifizierung .

request.method

Die request.method kann eine der Standardmethoden oder eine benutzerdefinierte Methode sein. Die Convenience-Methoden read und write existieren auch, um Schreibregeln zu vereinfachen, die für alle Nur-Lese- bzw. alle Nur-Schreib-Standardmethoden gelten.

request.params

Die request.params enthalten alle Daten, die sich nicht speziell auf die request.resource beziehen und für die Auswertung nützlich sein könnten. In der Praxis sollte diese Zuordnung für alle Standardmethoden leer sein und sollte Nicht-Ressourcendaten für benutzerdefinierte Methoden enthalten. Dienste müssen darauf achten, den Typ von Schlüsseln und Werten, die als Parameter dargestellt werden, nicht umzubenennen oder zu ändern.

request.path

Der request.path ist der Pfad für die resource . Der Pfad ist relativ zum Dienst. Pfadsegmente, die nicht URL-sichere Zeichen wie / enthalten, sind URL-codiert.

Die resource

Die resource ist der aktuelle Wert innerhalb des Dienstes, dargestellt als Karte von Schlüssel-Wert-Paaren. Das Verweisen auf eine resource innerhalb einer Bedingung führt zu höchstens einem Lesen des Werts aus dem Dienst. Diese Suche wird auf alle dienstbezogenen Kontingente für die Ressource angerechnet. Bei get -Anforderungen wird die resource nur bei Verweigerung auf das Kontingent angerechnet.

Operatoren und Operatorpriorität

Verwenden Sie die folgende Tabelle als Referenz für Operatoren und ihren entsprechenden Vorrang in Regeln für Cloud Firestore und Cloud Storage.

Gegeben sind beliebige Ausdrücke a und b , ein Feld f und ein Index i .

Operator Beschreibung Assoziativität
a[i] a() af Index, Aufruf, Feldzugriff links nach rechts
!a -a Unäre Negation rechts nach links
a/ba%ba*b Multiplikative Operatoren links nach rechts
a+b ab Additive Operatoren links nach rechts
a>ba>=ba Vergleichsoperatoren links nach rechts
a in b Existenz in Liste oder Karte links nach rechts
a is type Typvergleich, wobei der type bool, int, float, number, string, list, map, timestamp, duration, path oder latlng sein kann links nach rechts
a==ba!=b Vergleichsoperatoren links nach rechts
a && b Bedingtes UND links nach rechts
a || b Bedingtes ODER links nach rechts
a ? true_value : false_value Ternärer Ausdruck links nach rechts

Cloud-Speicher

Eine Bedingung ist ein boolescher Ausdruck, der festlegt, ob eine bestimmte Operation zugelassen oder verweigert werden soll. Die request und resource stellen Kontext für diese Bedingungen bereit.

Die request

Die request enthält die folgenden Felder und entsprechende Informationen:

request.auth

Ein JSON Web Token (JWT), das Authentifizierungsdaten von Firebase Authentication enthält. auth enthält eine Reihe von Standardansprüchen und alle benutzerdefinierten Ansprüche, die Sie über die Firebase-Authentifizierung erstellen. Erfahren Sie mehr über Firebase-Sicherheitsregeln und -Authentifizierung .

request.method

Die request.method kann eine der Standardmethoden oder eine benutzerdefinierte Methode sein. Die Convenience-Methoden read und write existieren auch, um Schreibregeln zu vereinfachen, die für alle Nur-Lese- bzw. alle Nur-Schreib-Standardmethoden gelten.

request.params

Die request.params enthalten alle Daten, die sich nicht speziell auf die request.resource beziehen und für die Auswertung nützlich sein könnten. In der Praxis sollte diese Zuordnung für alle Standardmethoden leer sein und sollte Nicht-Ressourcendaten für benutzerdefinierte Methoden enthalten. Dienste müssen darauf achten, den Typ von Schlüsseln und Werten, die als Parameter dargestellt werden, nicht umzubenennen oder zu ändern.

request.path

Der request.path ist der Pfad für die resource . Der Pfad ist relativ zum Dienst. Pfadsegmente, die nicht URL-sichere Zeichen wie / enthalten, sind URL-codiert.

Die resource

Die resource ist der aktuelle Wert innerhalb des Dienstes, dargestellt als Karte von Schlüssel-Wert-Paaren. Das Verweisen auf eine resource innerhalb einer Bedingung führt zu höchstens einem Lesen des Werts aus dem Dienst. Diese Suche wird auf alle dienstbezogenen Kontingente für die Ressource angerechnet. Bei get -Anforderungen wird die resource nur bei Verweigerung auf das Kontingent angerechnet.

Operatoren und Operatorpriorität

Verwenden Sie die folgende Tabelle als Referenz für Operatoren und ihren entsprechenden Vorrang in Regeln für Cloud Firestore und Cloud Storage.

Gegeben sind beliebige Ausdrücke a und b , ein Feld f und ein Index i .

Operator Beschreibung Assoziativität
a[i] a() af Index, Aufruf, Feldzugriff links nach rechts
!a -a Unäre Negation rechts nach links
a/ba%ba*b Multiplikative Operatoren links nach rechts
a+b ab Additive Operatoren links nach rechts
a>ba>=ba Vergleichsoperatoren links nach rechts
a in b Existenz in Liste oder Karte links nach rechts
a is type Typvergleich, wobei der type bool, int, float, number, string, list, map, timestamp, duration, path oder latlng sein kann links nach rechts
a==ba!=b Vergleichsoperatoren links nach rechts
a && b Bedingtes UND links nach rechts
a || b Bedingtes ODER links nach rechts
a ? true_value : false_value Ternärer Ausdruck links nach rechts

Echtzeit-Datenbank

Eine Bedingung ist ein boolescher Ausdruck, der festlegt, ob eine bestimmte Operation zugelassen oder verweigert werden soll. Sie können diese Bedingungen in Echtzeit-Datenbankregeln folgendermaßen definieren.

Vordefinierte Variablen

Es gibt eine Reihe hilfreicher, vordefinierter Variablen, auf die innerhalb einer Regeldefinition zugegriffen werden kann. Hier ist jeweils eine kurze Zusammenfassung:

Vordefinierte Variablen
jetzt Die aktuelle Zeit in Millisekunden seit der Linux-Epoche. Dies funktioniert besonders gut für die Validierung von Zeitstempeln, die mit firebase.database.ServerValue.TIMESTAMP des SDK erstellt wurden.
Wurzel Ein RuleDataSnapshot , der den Stammpfad in der Firebase-Datenbank darstellt, wie er vor dem versuchten Vorgang vorhanden war.
neue Daten Ein RuleDataSnapshot , der die Daten darstellt, wie sie nach dem versuchten Vorgang vorhanden wären. Es enthält die neuen Daten, die geschrieben werden, und vorhandene Daten.
Daten Ein RuleDataSnapshot , der die Daten darstellt, wie sie vor dem versuchten Vorgang vorhanden waren.
$-Variablen Ein Platzhalterpfad, der zur Darstellung von IDs und dynamischen untergeordneten Schlüsseln verwendet wird.
Authentifizierung Stellt die Tokennutzlast eines authentifizierten Benutzers dar.

Diese Variablen können überall in Ihren Regeln verwendet werden. Beispielsweise stellen die folgenden Sicherheitsregeln sicher, dass Daten, die in den /foo/ -Knoten geschrieben werden, eine Zeichenfolge mit weniger als 100 Zeichen sein müssen:

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

Datenbasierte Regeln

Alle Daten in Ihrer Datenbank können in Ihren Regeln verwendet werden. Mit den vordefinierten Variablen root , data und newData können Sie auf jeden Pfad zugreifen, wie er vor oder nach einem Schreibereignis vorhanden wäre.

Betrachten Sie dieses Beispiel, das Schreibvorgänge zulässt, solange der Wert des Knotens /allow_writes/ true ist, der übergeordnete Knoten kein readOnly Flag gesetzt hat und es in den neu geschriebenen Daten ein untergeordnetes Element namens foo gibt:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

Abfragebasierte Regeln

Obwohl Sie Regeln nicht als Filter verwenden können, können Sie den Zugriff auf Teilmengen von Daten einschränken, indem Sie Abfrageparameter in Ihren Regeln verwenden. query. Ausdrücke in Ihren Regeln, um basierend auf Abfrageparametern Lese- oder Schreibzugriff zu gewähren.

Beispielsweise verwendet die folgende abfragebasierte Regel benutzerbasierte Sicherheitsregeln und abfragebasierte Regeln, um den Zugriff auf Daten in der baskets -Sammlung nur auf die Warenkörbe zu beschränken, die der aktive Benutzer besitzt:

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

Die folgende Abfrage, die die Abfrageparameter in der Regel enthält, wäre erfolgreich:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

Abfragen, die die Parameter in der Regel nicht enthalten, würden jedoch mit einem PermissionDenied Fehler fehlschlagen:

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

Sie können auch abfragebasierte Regeln verwenden, um zu begrenzen, wie viele Daten ein Client durch Lesevorgänge herunterlädt.

Beispielsweise beschränkt die folgende Regel den Lesezugriff auf nur die ersten 1000 Ergebnisse einer Abfrage, sortiert nach Priorität:

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)

Die folgende query. Ausdrücke sind in Echtzeit-Datenbankregeln verfügbar.

Abfragebasierte Regelausdrücke
Ausdruck Typ Beschreibung
query.orderByKey
query.orderByPriority
query.orderByValue
boolesch True für nach Schlüssel, Priorität oder Wert geordnete Abfragen. Sonst falsch.
query.orderByChild Schnur
Null
Verwenden Sie eine Zeichenfolge, um den relativen Pfad zu einem untergeordneten Knoten darzustellen. Beispiel: query.orderByChild === "address/zip" . Wenn die Abfrage nicht nach einem untergeordneten Knoten geordnet ist, ist dieser Wert null.
query.startAt
query.endAt
query.equalTo
Schnur
Nummer
boolesch
Null
Ruft die Grenzen der ausgeführten Abfrage ab oder gibt null zurück, wenn kein gebundener Satz vorhanden ist.
query.limitToFirst
query.limitToLast
Nummer
Null
Ruft das Limit für die ausgeführte Abfrage ab oder gibt null zurück, wenn kein Limit festgelegt ist.

Betreiber

Echtzeit-Datenbankregeln unterstützen eine Reihe von Operatoren , die Sie verwenden können, um Variablen in der Bedingungsanweisung zu kombinieren. Die vollständige Liste der Operatoren finden Sie in der Referenzdokumentation .

Bedingungen schaffen

Ihre tatsächlichen Bedingungen variieren je nach dem Zugriff, den Sie gewähren möchten. Regeln bieten absichtlich ein enormes Maß an Flexibilität, sodass die Regeln Ihrer App letztendlich so einfach oder so komplex sein können, wie Sie sie benötigen.

Einige Anleitungen zum Erstellen einfacher, produktionsbereiter Regeln finden Sie unter Grundlegende Sicherheitsregeln .