Ta strona opiera się na koncepcjach w artykułach Tworzenie reguł bezpieczeństwa i Pisanie warunków dla reguł bezpieczeństwa , aby wyjaśnić, w jaki sposób reguły bezpieczeństwa Cloud Firestore wchodzą w interakcje z zapytaniami. Przyjrzymy się bliżej, w jaki sposób reguły bezpieczeństwa wpływają na zapytania, które możesz pisać, i opisano, jak upewnić się, że zapytania używają tych samych ograniczeń, co reguły bezpieczeństwa. Na tej stronie opisano również sposób pisania reguł zabezpieczeń zezwalających na zapytania lub odrzucających je na podstawie właściwości zapytania, takich jak limit
i orderBy
.
Reguły nie są filtrami
Podczas pisania zapytań w celu pobrania dokumentów należy pamiętać, że reguły bezpieczeństwa nie są filtrami — zapytania to wszystko albo nic. Aby zaoszczędzić czas i zasoby, Cloud Firestore ocenia zapytanie pod kątem potencjalnego zestawu wyników zamiast rzeczywistych wartości pól we wszystkich dokumentach. Jeśli zapytanie mogłoby potencjalnie zwrócić dokumenty, których klient nie ma uprawnień do odczytu, całe żądanie zakończy się niepowodzeniem.
Zapytania i reguły bezpieczeństwa
Jak pokazują poniższe przykłady, musisz napisać swoje zapytania, aby pasowały do ograniczeń twoich reguł bezpieczeństwa.
Zabezpieczaj i wysyłaj zapytania do dokumentów w oparciu o auth.uid
Poniższy przykład pokazuje, jak napisać zapytanie w celu pobrania dokumentów chronionych przez regułę bezpieczeństwa. Rozważmy bazę danych zawierającą zbiór dokumentów story
:
/historie/{identyfikator opowieści}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
Oprócz pól title
i content
każdy dokument zawiera pola author
i published
, których można używać do kontroli dostępu. W tych przykładach przyjęto założenie, że aplikacja korzysta z uwierzytelniania Firebase , aby ustawić pole author
na identyfikator UID użytkownika, który utworzył dokument. Uwierzytelnianie Firebase wypełnia również zmienną request.auth
w regułach bezpieczeństwa.
Poniższa reguła bezpieczeństwa wykorzystuje zmienne request.auth
i resource.data
w celu ograniczenia dostępu do odczytu i zapisu dla każdej story
do jej autora:
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ę, która pokazuje użytkownikowi listę dokumentów story
, których jest autorem. Możesz oczekiwać, że możesz użyć następującego zapytania do wypełnienia tej strony. Jednak to zapytanie zakończy się niepowodzeniem, ponieważ nie zawiera tych samych ograniczeń, co reguły bezpieczeństwa:
Nieprawidłowy : ograniczenia zapytania nie odpowiadają ograniczeniom reguł bezpieczeństwa
// This query will fail
db.collection("stories").get()
Zapytanie kończy się niepowodzeniem , nawet jeśli bieżący użytkownik jest autorem wszystkich dokumentów story
. Przyczyną takiego zachowania jest to, że kiedy Cloud Firestore stosuje Twoje reguły bezpieczeństwa, ocenia zapytanie pod kątem potencjalnego zestawu wyników, a nie rzeczywistych właściwości dokumentów w Twojej bazie danych. Jeśli kwerenda mogłaby potencjalnie zawierać dokumenty, które naruszają twoje zasady bezpieczeństwa, kwerenda zakończy się niepowodzeniem.
W przeciwieństwie do tego następujące zapytanie powiedzie się, ponieważ zawiera to samo ograniczenie dotyczące pola author
, co reguły bezpieczeństwa:
Prawidłowy : ograniczenia zapytania są zgodne z ograniczeniami reguł zabezpieczeń
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Zabezpieczaj i wysyłaj zapytania do dokumentów na podstawie pola
Aby dokładniej zademonstrować interakcję między zapytaniami a regułami, poniższe reguły bezpieczeństwa rozszerzają dostęp do odczytu dla kolekcji stories
, aby umożliwić każdemu użytkownikowi odczytywanie dokumentów story
, w których pole published
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 publikowane strony musi zawierać te same ograniczenia, co zasady 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 reguły bezpieczeństwa i może odczytywać 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ównania 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 : Query 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żny : 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ń dotyczących zapytań
Twoje reguły bezpieczeństwa mogą również akceptować lub odrzucać zapytania na podstawie ich ograniczeń. Zmienna request.query
zawiera właściwości limit
, offset
i orderBy
zapytania. Na przykład Twoje 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 pisać reguły zabezpieczeń, które oceniają ograniczenia nałożone na zapytania. Ten przykład rozszerza poprzedni zestaw reguł stories
o następujące zmiany:
- Zestaw reguł rozdziela regułę odczytu 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 dotyczy zapytań. Sprawdza również limit zapytania, a następnie odrzuca każde zapytanie bez limitu lub z limitem większym niż 10. - Zestaw reguł definiuje funkcję
authorOrPublished()
w celu uniknięcia 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 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 sposób zabezpieczania zapytań grupy kolekcji przy użyciu reguł zabezpieczeń.
Zabezpieczaj i przeszukuj dokumenty na podstawie grup kolekcji
W swoich regułach bezpieczeństwa musisz wyraźnie zezwolić na zapytania dotyczące grupy kolekcji, pisząc regułę dla grupy kolekcji:
- Upewnij się
rules_version = '2';
to pierwsza linia Twojego zestawu reguł. Zapytania grupy 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}/posty/{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 pojedynczego forum:
db.collection("forums/technology/posts").get()
Ale co, jeśli chcesz pokazać bieżącemu użytkownikowi jego posty na wszystkich forach? Możesz użyć zapytania o grupę 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 ze posts
identyfikacyjnymi, niezależnie od hierarchii. Na przykład te zasady dotyczą wszystkich następujących kolekcji posts
:
-
/posts/{postid}
-
/forums/{forumid}/posts/{postid}
-
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Bezpieczne zapytania grup kolekcji na podstawie pola
Podobnie jak zapytania dotyczące pojedynczej kolekcji, zapytania dotyczące grup kolekcji muszą również spełniać ograniczenia określone przez reguły bezpieczeństwa. Na przykład możemy dodać published
pole do każdego posta na forum, tak jak zrobiliśmy to w powyższym przykładzie stories
:
/forums/{forumid}/posty/{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
na podstawie published
statusu i author
postu:
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;
}
}
}
Korzystając z tych reguł, klienci WWW, 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 pobrać opublikowane posty autora na wszystkich forach:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
Autorzy mogą pobrać wszystkie swoje opublikowane i nieopublikowane posty na wszystkich forach:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Zabezpiecz dokumenty i przeszukuj je na podstawie grupy kolekcji i ścieżki dokumentu
W niektórych przypadkach możesz chcieć ograniczyć zapytania grupy kolekcji na podstawie ścieżki dokumentu. Aby utworzyć te ograniczenia, możesz użyć tych samych technik zabezpieczania i wysyłania zapytań do dokumentów na podstawie pola.
Rozważmy aplikację, która śledzi transakcje każdego użytkownika na kilku giełdach akcji i 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
. Chociaż wiemy, który użytkownik jest właścicielem dokumentu transaction
ze ścieżki dokumentu, duplikujemy te informacje w każdym dokumencie transaction
, ponieważ pozwala nam to zrobić dwie rzeczy:
Pisz zapytania grupy 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 zbierania
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 walidację danych dla pola 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
- Aby zapoznać się z bardziej szczegółowym przykładem kontroli dostępu opartej na rolach, zobacz Zabezpieczanie dostępu do danych dla użytkowników i grup .
- Przeczytaj odniesienie do zasad bezpieczeństwa .