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
unddelete
. Die bequemenread
undwrite
ermöglichen einen breiten Lese- und Schreibzugriff 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
unddelete
. Die bequemenread
undwrite
ermöglichen einen breiten Lese- und Schreibzugriff 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
undwrite
gewähren breiten Lese- und Schreibzugriff, währendvalidate
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 Methodenread
undwrite
. - 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 vonrequest.path
. - Vollständige Übereinstimmungen: Das
path
stimmt mit dem gesamtenrequest.path
überein.
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 dermatch
Anweisung alsstring
zugegriffen 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 dermatch
Anweisung alspath
zugegriffen werden.
Erlauben
Der match
Block enthält eine oder mehrere allow
Anweisungen. Dies sind Ihre eigentlichen Regeln. Sie können allow
auf eine 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 read
. Wenn die allow
Anweisung jedoch keine Bedingung enthält, lässt sie die Anfrage für diese Methode immer zu.
Wenn eine der allow
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 dieresource
und integrierte Funktionen wieget()
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üsselwortlet
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 Methodenread
undwrite
. - 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 vonrequest.path
. - Vollständige Übereinstimmungen: Das
path
stimmt mit dem gesamtenrequest.path
überein.
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 dermatch
Anweisung alsstring
zugegriffen 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 dermatch
Anweisung alspath
zugegriffen werden.
Erlauben
Der match
Block enthält eine oder mehrere allow
Anweisungen. Dies sind Ihre eigentlichen Regeln. Sie können allow
auf eine 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 read
. Wenn die allow
Anweisung jedoch keine Bedingung enthält, lässt sie die Anfrage für diese Methode immer zu.
Wenn eine der allow
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 dieresource
und integrierte Funktionen wieget()
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üsselwortlet
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 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 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 .