Ta strona opiera się na koncepcjach z Strukturyzacji reguł bezpieczeństwa i Pisania warunków dla reguł bezpieczeństwa , aby wyjaśnić, w jaki sposób reguły bezpieczeństwa Cloud Firestore wchodzą w interakcję z zapytaniami. Przyjrzyjmy się bliżej, jak reguły bezpieczeństwa wpływają na zapytania, które możesz pisać, i opisano, w jaki sposób zapewnić, że zapytania będą używać tych samych ograniczeń, co reguły bezpieczeństwa. Na tej stronie opisano również sposób pisania reguł zabezpieczeń zezwalających na zapytania lub blokujących je na podstawie właściwości zapytania, takich jak limit
i orderBy
.
Reguły to nie filtry
Pisząc zapytania w celu pobrania dokumentów, należy pamiętać, że reguły bezpieczeństwa to nie filtry — zapytania oznaczają wszystko albo nic. Aby zaoszczędzić czas i zasoby, Cloud Firestore ocenia zapytanie na podstawie potencjalnego zestawu wyników, a nie rzeczywistych wartości pól dla wszystkich Twoich dokumentów. Jeśli zapytanie mogłoby potencjalnie zwrócić dokumenty, do których klient nie ma uprawnień, całe żądanie kończy się niepowodzeniem.
Zapytania i zasady bezpieczeństwa
Jak pokazują poniższe przykłady, musisz pisać zapytania tak, aby pasowały do ograniczeń reguł bezpieczeństwa.
Zabezpiecz i przeszukuj dokumenty w oparciu o auth.uid
Poniższy przykład ilustruje sposób napisania zapytania w celu pobrania dokumentów chronionych regułą zabezpieczeń. Rozważmy bazę danych zawierającą zbiór dokumentów story
:
/historie/{historiaid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
Oprócz pól title
i content
w każdym dokumencie przechowywane są pola author
i published
, które można wykorzystać do kontroli dostępu. W tych przykładach założono, że aplikacja korzysta z uwierzytelniania Firebase , aby ustawić pole author
na UID użytkownika, który utworzył dokument. Uwierzytelnianie Firebase wypełnia również zmienną request.auth
w regułach bezpieczeństwa.
Następująca reguła bezpieczeństwa wykorzystuje zmienne request.auth
i resource.data
w celu ograniczenia dostępu do odczytu i zapisu każdej story
jego autorowi:
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;
}
}
}
Załóżmy, że Twoja aplikacja zawiera stronę wyświetlającą użytkownikowi listę dokumentów z story
, których jest autorem. Można się spodziewać, że do wypełnienia tej strony można użyć następującego zapytania. Jednak to zapytanie zakończy się niepowodzeniem, ponieważ nie zawiera tych samych ograniczeń, co reguły bezpieczeństwa:
Nieprawidłowe : ograniczenia zapytania nie są zgodne z ograniczeniami reguł bezpieczeństwa
// This query will fail
db.collection("stories").get()
Zapytanie kończy się niepowodzeniem , nawet jeśli bieżący użytkownik jest faktycznie autorem każdego dokumentu story
. Powodem tego zachowania jest to, że gdy Cloud Firestore stosuje reguły bezpieczeństwa, ocenia zapytanie pod kątem potencjalnego zestawu wyników, a nie rzeczywistych właściwości dokumentów w bazie danych. Jeśli zapytanie może potencjalnie zawierać dokumenty naruszające zasady bezpieczeństwa, zapytanie zakończy się niepowodzeniem.
Natomiast poniższe zapytanie powiodło się, ponieważ zawiera takie samo ograniczenie pola author
, jak reguły bezpieczeństwa:
Prawidłowe : ograniczenia zapytań są zgodne z ograniczeniami reguł bezpieczeństwa
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Zabezpieczaj i wysyłaj zapytania do dokumentów w oparciu o pola
Aby jeszcze bardziej zademonstrować interakcję między zapytaniami i regułami, poniższe reguły bezpieczeństwa rozszerzają dostęp do odczytu kolekcji stories
, aby umożliwić każdemu użytkownikowi czytanie dokumentów story
, w których published
pole ma wartość true
.
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;
}
}
}
Zapytanie o opublikowane strony musi zawierać te same ograniczenia, co reguły bezpieczeństwa:
db.collection("stories").where("published", "==", true).get()
Ograniczenie zapytania .where("published", "==", true)
gwarantuje, że resource.data.published
ma true
dla każdego wyniku. Dlatego to zapytanie spełnia zasady bezpieczeństwa i może odczytać dane.
OR
zapytania
Podczas oceniania zapytania logicznego OR
( or
, in
lub array-contains-any
) względem zestawu reguł Cloud Firestore ocenia każdą wartość porównania osobno. Każda wartość porównawcza musi spełniać ograniczenia reguły bezpieczeństwa. Na przykład dla następującej reguły:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
Nieprawidłowy : zapytanie nie gwarantuje, że x > 5
dla wszystkich potencjalnych dokumentów
// 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])
)
Ważne : zapytanie gwarantuje, że x > 5
dla wszystkich potencjalnych dokumentów
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
Ocena ograniczeń zapytań
Reguły bezpieczeństwa mogą także akceptować lub odrzucać zapytania w oparciu o swoje ograniczenia. Zmienna request.query
zawiera właściwości limit
, offset
i orderBy
zapytania. Na przykład reguły bezpieczeństwa mogą odrzucić każde zapytanie, które nie ogranicza maksymalnej liczby pobieranych dokumentów do określonego zakresu:
allow list: if request.query.limit <= 10;
Poniższy zestaw reguł pokazuje, jak napisać reguły bezpieczeństwa, które oceniają ograniczenia nałożone na zapytania. Ten przykład rozszerza poprzedni zestaw reguł stories
o następujące zmiany:
- Zestaw reguł dzieli regułę read na reguły
get
ilist
. - Reguła
get
ogranicza pobieranie pojedynczych dokumentów do dokumentów publicznych lub dokumentów, których autorem jest użytkownik. - Reguła
list
stosuje te same ograniczenia, coget
, ale w przypadku zapytań. Sprawdza również limit zapytań, a następnie odrzuca każde zapytanie bez limitu lub z limitem większym niż 10. - Zestaw reguł definiuje funkcję
authorOrPublished()
, aby uniknąć powielania kodu.
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;
}
}
}
Zapytania dotyczące grup kolekcji i reguły bezpieczeństwa
Domyślnie zapytania są ograniczone do pojedynczej kolekcji i pobierają wyniki tylko z tej kolekcji. Za pomocą zapytań o grupę kolekcji można pobrać wyniki z grupy kolekcji składającej się ze wszystkich kolekcji o tym samym identyfikatorze. W tej sekcji opisano, jak zabezpieczyć zapytania dotyczące grup kolekcji za pomocą reguł bezpieczeństwa.
Zabezpiecz dokumenty i przeszukuj je w oparciu o grupy kolekcji
W regułach bezpieczeństwa musisz jawnie zezwolić na zapytania dotyczące grup kolekcji, pisząc regułę dla grupy kolekcji:
- Upewnij się
rules_version = '2';
to pierwsza linia zestawu reguł. Zapytania dotyczące grup kolekcji wymagają nowego, rekurencyjnego zachowania symboli wieloznacznych{name=**}
reguł zabezpieczeń w wersji 2. - Napisz regułę dla swojej grupy kolekcji, używając
match /{path=**}/ [COLLECTION_ID] /{doc}
.
Rozważmy na przykład forum zorganizowane w dokumenty forum
zawierające podzbiory posts
:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
W tej aplikacji umożliwiamy edytowanie postów przez ich właścicieli i odczytywanie przez uwierzytelnionych użytkowników:
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;
}
}
}
Każdy uwierzytelniony użytkownik może pobrać posty z dowolnego forum:
db.collection("forums/technology/posts").get()
Ale co, jeśli chcesz pokazać aktualnemu użytkownikowi jego posty na wszystkich forach? Możesz użyć zapytania grupy kolekcji , aby pobrać wyniki ze wszystkich kolekcji posts
:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
W swoich regułach bezpieczeństwa musisz zezwolić na to zapytanie, pisząc regułę odczytu lub listy dla grupy kolekcji posts
:
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;
}
}
}
Pamiętaj jednak, że te zasady będą miały zastosowanie do wszystkich kolekcji z posts
identyfikacyjnymi, niezależnie od hierarchii. Na przykład te reguły dotyczą wszystkich następujących kolekcji posts
:
-
/posts/{postid}
-
/forums/{forumid}/posts/{postid}
-
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Bezpieczne zapytania dotyczące grup kolekcji na podstawie pola
Podobnie jak zapytania dotyczące pojedynczego zbioru, zapytania dotyczące grup kolekcji muszą również spełniać ograniczenia określone przez reguły zabezpieczeń. Na przykład możemy dodać published
pole do każdego wpisu na forum, tak jak to zrobiliśmy w powyższym przykładzie stories
:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
Następnie możemy napisać reguły dla grupy kolekcji posts
w oparciu o status published
i author
posta:
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;
}
}
}
Dzięki tym regułom klienci sieci Web, Apple i Android mogą wykonywać następujące zapytania:
Każdy może pobrać opublikowane posty na forum:
db.collection("forums/technology/posts").where('published', '==', true).get()
Każdy może przeglądać posty autora opublikowane na wszystkich forach:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
Autorzy mogą odzyskać wszystkie swoje opublikowane i niepublikowane posty na wszystkich forach:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Zabezpieczaj dokumenty i przeszukuj je w oparciu o grupę kolekcji i ścieżkę dokumentu
W niektórych przypadkach możesz chcieć ograniczyć zapytania dotyczące grup kolekcji na podstawie ścieżki dokumentu. Aby utworzyć te ograniczenia, można użyć tych samych technik zabezpieczania dokumentów i wysyłania zapytań na podstawie pól.
Rozważ aplikację, która śledzi transakcje każdego użytkownika na kilku giełdach i giełdach kryptowalut:
/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",
}
Zwróć uwagę na pole user
. Mimo że ze ścieżki dokumentu wiemy, który użytkownik jest właścicielem dokumentu transaction
, powielamy tę informację w każdym dokumencie transaction
, ponieważ pozwala nam to na dwie rzeczy:
Twórz zapytania dotyczące grup kolekcji, które są ograniczone do dokumentów zawierających określony
/users/{userid}
w ścieżce dokumentu. Na przykład: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)
Wymuś to ograniczenie dla wszystkich zapytań w grupie gromadzenia
transactions
, aby jeden użytkownik nie mógł pobrać dokumentówtransaction
innego użytkownika.
Egzekwujemy to ograniczenie w naszych zasadach bezpieczeństwa i uwzględniamy weryfikację danych w polu 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
}
}
}
Następne kroki
- Bardziej szczegółowy przykład kontroli dostępu opartej na rolach można znaleźć w sekcji Zabezpieczanie dostępu do danych dla użytkowników i grup .
- Przeczytaj odniesienia do reguł bezpieczeństwa .