Diese Seite baut auf den Konzepten in „Strukturieren von Sicherheitsregeln“ und „Schreiben von Bedingungen für Sicherheitsregeln“ auf , um zu erklären, wie Cloud Firestore-Sicherheitsregeln mit Abfragen interagieren. Es wird genauer untersucht, wie sich Sicherheitsregeln auf die Abfragen auswirken, die Sie schreiben können, und es wird beschrieben, wie Sie sicherstellen können, dass Ihre Abfragen dieselben Einschränkungen wie Ihre Sicherheitsregeln verwenden. Auf dieser Seite wird außerdem beschrieben, wie Sie Sicherheitsregeln schreiben, um Abfragen basierend auf Abfrageeigenschaften wie limit
und orderBy
zuzulassen oder abzulehnen.
Regeln sind keine Filter
Bedenken Sie beim Schreiben von Abfragen zum Abrufen von Dokumenten, dass es sich bei Sicherheitsregeln nicht um Filter handelt – bei Abfragen geht es um alles oder nichts. Um Ihnen Zeit und Ressourcen zu sparen, wertet Cloud Firestore eine Abfrage anhand ihres potenziellen Ergebnissatzes aus und nicht anhand der tatsächlichen Feldwerte für alle Ihre Dokumente. Wenn eine Abfrage möglicherweise Dokumente zurückgibt, für die der Client keine Leseberechtigung hat, schlägt die gesamte Anfrage fehl.
Abfragen und Sicherheitsregeln
Wie die folgenden Beispiele zeigen, müssen Sie Ihre Abfragen so schreiben, dass sie den Einschränkungen Ihrer Sicherheitsregeln entsprechen.
Sichern und Abfragen von Dokumenten basierend auf auth.uid
Das folgende Beispiel zeigt, wie eine Abfrage zum Abrufen von Dokumenten geschrieben wird, die durch eine Sicherheitsregel geschützt sind. Stellen Sie sich eine Datenbank vor, die eine Sammlung von story
Dokumenten enthält:
/stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
Zusätzlich zu den title
und content
speichert jedes Dokument die Felder author
“ und published
“, die für die Zugriffskontrolle verwendet werden. In diesen Beispielen wird davon ausgegangen, dass die App die Firebase-Authentifizierung verwendet, um das author
auf die UID des Benutzers festzulegen, der das Dokument erstellt hat. Die Firebase-Authentifizierung füllt auch die Variable request.auth
in den Sicherheitsregeln auf.
Die folgende Sicherheitsregel verwendet die Variablen request.auth
und resource.data
, um den Lese- und Schreibzugriff für jede story
auf ihren Autor zu beschränken:
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Angenommen, Ihre App enthält eine Seite, die dem Benutzer eine Liste der von ihm verfassten story
Dokumente anzeigt. Sie könnten erwarten, dass Sie die folgende Abfrage verwenden könnten, um diese Seite zu füllen. Diese Abfrage schlägt jedoch fehl, da sie nicht dieselben Einschränkungen wie Ihre Sicherheitsregeln enthält:
Ungültig : Abfrageeinschränkungen stimmen nicht mit den Sicherheitsregelneinschränkungen überein
// This query will fail
db.collection("stories").get()
Die Abfrage schlägt auch dann fehl, wenn der aktuelle Benutzer tatsächlich der Autor jedes story
Dokuments ist. Der Grund für dieses Verhalten liegt darin, dass Cloud Firestore bei der Anwendung Ihrer Sicherheitsregeln die Abfrage anhand ihres potenziellen Ergebnissatzes und nicht anhand der tatsächlichen Eigenschaften von Dokumenten in Ihrer Datenbank auswertet. Wenn eine Abfrage möglicherweise Dokumente enthält, die gegen Ihre Sicherheitsregeln verstoßen, schlägt die Abfrage fehl.
Im Gegensatz dazu ist die folgende Abfrage erfolgreich, da sie dieselbe Einschränkung für das Feld author
enthält wie die Sicherheitsregeln:
Gültig : Abfrageeinschränkungen stimmen mit Sicherheitsregeleinschränkungen überein
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Sichern und Abfragen von Dokumenten basierend auf einem Feld
Um die Interaktion zwischen Abfragen und Regeln weiter zu veranschaulichen, erweitern die folgenden Sicherheitsregeln den Lesezugriff für die stories
Sammlung, um jedem Benutzer das Lesen story
Dokumenten zu ermöglichen, bei denen das published
Feld auf true
gesetzt ist.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Die Abfrage nach veröffentlichten Seiten muss dieselben Einschränkungen enthalten wie die Sicherheitsregeln:
db.collection("stories").where("published", "==", true).get()
Die Abfrageeinschränkung .where("published", "==", true)
garantiert, dass resource.data.published
für jedes Ergebnis true
ist. Daher erfüllt diese Abfrage die Sicherheitsregeln und darf Daten lesen.
OR
Abfragen
Bei der Auswertung einer logischen OR
Abfrage ( or
, in
oder array-contains-any
) anhand eines Regelsatzes wertet Cloud Firestore jeden Vergleichswert separat aus. Jeder Vergleichswert muss die Einschränkungen der Sicherheitsregeln erfüllen. Zum Beispiel für die folgende Regel:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
Ungültig : Die Abfrage garantiert nicht, dass x > 5
für alle potenziellen Dokumente ist
// These queries will fail
query(db.collection("mydocuments"),
or(where("x", "==", 1),
where("x", "==", 6)
)
)
query(db.collection("mydocuments"),
where("x", "in", [1, 3, 6, 42, 99])
)
Gültig : Die Abfrage garantiert, dass x > 5
für alle potenziellen Dokumente ist
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
Auswerten von Einschränkungen für Abfragen
Ihre Sicherheitsregeln können Abfragen basierend auf ihren Einschränkungen auch akzeptieren oder ablehnen. Die Variable request.query
enthält die limit
, offset
und orderBy
einer Abfrage. Ihre Sicherheitsregeln können beispielsweise jede Abfrage ablehnen, die die maximale Anzahl der abgerufenen Dokumente nicht auf einen bestimmten Bereich begrenzt:
allow list: if request.query.limit <= 10;
Der folgende Regelsatz zeigt, wie Sicherheitsregeln geschrieben werden, die Einschränkungen für Abfragen bewerten. Dieses Beispiel erweitert den vorherigen stories
Regelsatz um die folgenden Änderungen:
- Der Regelsatz unterteilt die Leseregel in Regeln für
get
undlist
. - Die
get
Regel beschränkt den Abruf einzelner Dokumente auf öffentliche Dokumente oder Dokumente, die der Benutzer erstellt hat. - Die
list
wendet dieselben Einschränkungen wieget
an, jedoch für Abfragen. Außerdem wird das Abfragelimit überprüft und dann jede Abfrage ohne oder mit einem Limit von mehr als 10 abgelehnt. - Der Regelsatz definiert eine
authorOrPublished()
Funktion, um Codeduplizierung zu vermeiden.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
Sammlungsgruppenabfragen und Sicherheitsregeln
Standardmäßig sind Abfragen auf eine einzelne Sammlung beschränkt und rufen nur Ergebnisse aus dieser Sammlung ab. Mit Sammlungsgruppenabfragen können Sie Ergebnisse aus einer Sammlungsgruppe abrufen, die aus allen Sammlungen mit derselben ID besteht. In diesem Abschnitt wird beschrieben, wie Sie Ihre Sammlungsgruppenabfragen mithilfe von Sicherheitsregeln sichern.
Sichern und Abfragen von Dokumenten basierend auf Sammlungsgruppen
In Ihren Sicherheitsregeln müssen Sie Abfragen von Sammlungsgruppen explizit zulassen, indem Sie eine Regel für die Sammlungsgruppe schreiben:
- Stellen Sie sicher,
rules_version = '2';
ist die erste Zeile Ihres Regelsatzes. Sammlungsgruppenabfragen erfordern das neue rekursive Platzhalterverhalten{name=**}
der Sicherheitsregeln Version 2. - Schreiben Sie eine Regel für Ihre Sammlungsgruppe mit
match /{path=**}/ [COLLECTION_ID] /{doc}
.
Stellen Sie sich beispielsweise ein Forum vor, das in forum
unterteilt ist, die Untersammlungen posts
enthalten:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
In dieser Anwendung machen wir Beiträge für ihre Eigentümer bearbeitbar und für authentifizierte Benutzer lesbar:
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Jeder authentifizierte Benutzer kann die Beiträge jedes einzelnen Forums abrufen:
db.collection("forums/technology/posts").get()
Was aber, wenn Sie dem aktuellen Benutzer seine Beiträge in allen Foren zeigen möchten? Sie können eine Sammlungsgruppenabfrage verwenden, um Ergebnisse aus allen posts
abzurufen:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
In Ihren Sicherheitsregeln müssen Sie diese Abfrage zulassen, indem Sie eine Lese- oder Listenregel für die Sammlungsgruppe posts
schreiben:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Beachten Sie jedoch, dass diese Regeln für alle Sammlungen mit ID- posts
gelten, unabhängig von der Hierarchie. Diese Regeln gelten beispielsweise für alle folgenden posts
:
-
/posts/{postid}
-
/forums/{forumid}/posts/{postid}
-
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Sichere Sammlungsgruppenabfragen basierend auf einem Feld
Wie Abfragen einzelner Sammlungen müssen auch Abfragen von Sammlungsgruppen die durch Ihre Sicherheitsregeln festgelegten Einschränkungen erfüllen. Beispielsweise können wir jedem Forumsbeitrag ein published
Feld hinzufügen, wie wir es im obigen stories
Beispiel getan haben:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
Anschließend können wir Regeln für die posts
basierend auf dem published
und dem author
schreiben:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
Mit diesen Regeln können Web-, Apple- und Android-Clients die folgenden Abfragen durchführen:
Jeder kann veröffentlichte Beiträge in einem Forum abrufen:
db.collection("forums/technology/posts").where('published', '==', true).get()
Jeder kann die veröffentlichten Beiträge eines Autors in allen Foren abrufen:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
Autoren können alle ihre veröffentlichten und unveröffentlichten Beiträge in allen Foren abrufen:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Sichern und Abfragen von Dokumenten basierend auf Sammlungsgruppe und Dokumentpfad
In einigen Fällen möchten Sie möglicherweise Sammlungsgruppenabfragen basierend auf dem Dokumentpfad einschränken. Um diese Einschränkungen zu erstellen, können Sie dieselben Techniken zum Sichern und Abfragen von Dokumenten basierend auf einem Feld verwenden.
Stellen Sie sich eine Anwendung vor, die die Transaktionen jedes Benutzers zwischen mehreren Aktien- und Kryptowährungsbörsen verfolgt:
/users/{userid}/exchange/{exchangeid}/transactions/{transaction}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
Beachten Sie das user
. Obwohl wir aus dem Pfad des Dokuments wissen, welcher Benutzer ein transaction
besitzt, duplizieren wir diese Informationen in jedem transaction
, weil wir dadurch zwei Dinge tun können:
Schreiben Sie Sammlungsgruppenabfragen, die auf Dokumente beschränkt sind, deren Dokumentpfad eine bestimmte
/users/{userid}
enthält. Zum Beispiel:var user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
Erzwingen Sie diese Einschränkung für alle Abfragen in der
transactions
, sodass ein Benutzertransaction
eines anderen Benutzers nicht abrufen kann.
Wir erzwingen diese Einschränkung in unseren Sicherheitsregeln und integrieren eine Datenvalidierung für das user
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
Nächste Schritte
- Ein ausführlicheres Beispiel einer rollenbasierten Zugriffskontrolle finden Sie unter Sichern des Datenzugriffs für Benutzer und Gruppen .
- Lesen Sie die Referenz zu den Sicherheitsregeln .