Na tej stronie znajdziesz informacje o tym, jak Cloud Firestore Security Rules współdziałają z zapytaniami. Opierają się one na pojęciach opisanych w artykułach Struktura reguł zabezpieczeń i Pisanie warunków reguł zabezpieczeń. Przyjrzymy się bliżej temu, jak reguły zabezpieczeń wpływają na zapytania, które możesz pisać, i opiszemy, jak zapewnić, że zapytania będą używać tych samych ograniczeń co reguły zabezpieczeń. Na tej stronie opisano też, jak pisać reguły zabezpieczeń, aby zezwalać na zapytania lub je odrzucać na podstawie właściwości zapytania, takich jak limit i orderBy.
prompt AI dla pomocy AI
Aby uzyskać pomoc AI, skopiuj poniższy prompt do agenta kodowania AI (takiego jak Gemini w Android Studio, Antigravity, Claude Code, Codex czy Cursor). Możesz dostosować prompta i wprowadzać zmiany z agentem. Szczegółowe informacje o instalacji znajdziesz w artykule Umiejętności agenta Firebase.
Help me use Firebase in my app.
1. Make sure that **Firebase agent skills** are installed and updated. For Claude Code, Codex, or Cursor agents, help me install the Firebase plugin. For other agents, run `npx skills add firebase/agent-skills`. Always try to use **Firebase agent skills** for Firebase-related tasks.
2. Help me write, validate, and deploy Firebase Security Rules to protect my app's Firestore data.
Reguły to nie filtry
Pisząc zapytania do pobierania dokumentów, pamiętaj, że reguły zabezpieczeń nie są filtrami – zapytania działają na zasadzie „wszystko albo nic”. Aby zaoszczędzić czas i zasoby, Reguły oceniają zapytanie na podstawie potencjalnego zestawu wyników, a nie rzeczywistych wartości pól we wszystkich dokumentach. Jeśli zapytanie może potencjalnie zwrócić dokumenty, do których klient nie ma uprawnień do odczytu, całe żądanie zakończy się niepowodzeniem.
Zapytania i reguły zabezpieczeń
Jak pokazują poniższe przykłady, zapytania muszą być napisane tak, aby spełniały ograniczenia reguł zabezpieczeń.
Zabezpieczanie dokumentów i tworzenie zapytań na podstawie auth.uid
Poniższy przykład pokazuje, jak napisać zapytanie, aby pobrać dokumenty chronione przez regułę zabezpieczeń. Rozważmy bazę danych zawierającą kolekcję dokumentów story:
/stories/{storyid}
{
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óre służą do kontroli dostępu. W tych przykładach zakładamy, że aplikacja używa Uwierzytelniania Firebase do ustawiania pola author na identyfikator UID użytkownika, który utworzył dokument. Uwierzytelnianie Firebase wypełnia też zmienną request.auth w regułach zabezpieczeń.
Ta reguła zabezpieczeń używa zmiennych request.auth i resource.data, aby ograniczyć uprawnienia do odczytu i zapisu każdego elementu story do jego 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ę, na której użytkownik widzi listę dokumentów story, których jest autorem. Można by się spodziewać, że do wypełnienia tej strony można użyć tego zapytania. To zapytanie nie powiedzie się, ponieważ nie zawiera tych samych ograniczeń co reguły zabezpieczeń:
Nieprawidłowe: ograniczenia zapytania nie pasują do ograniczeń reguł zabezpieczeń.
// This query will fail
db.collection("stories").get()
Zapytanie nie powiedzie się, nawet jeśli bieżący użytkownik jest autorem każdego dokumentu story. Dzieje się tak, ponieważ gdy reguły stosują reguły zabezpieczeń, oceniają zapytanie pod kątem potencjalnego zbioru wyników, a nie rzeczywistych właściwości dokumentów w bazie danych. Jeśli zapytanie potencjalnie może obejmować dokumenty, które naruszają reguły zabezpieczeń, nie powiedzie się.
Z kolei to zapytanie zostanie wykonane, ponieważ zawiera to samo ograniczenie dotyczące pola author co reguły zabezpieczeń:
Prawidłowe: ograniczenia zapytania są zgodne z ograniczeniami reguł zabezpieczeń.
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Zabezpieczanie dokumentów i wykonywanie zapytań na ich temat na podstawie pola
Aby lepiej zilustrować interakcję między zapytaniami i regułami, poniższe reguły zabezpieczeń rozszerzają uprawnienia do odczytu kolekcji stories, aby umożliwić każdemu użytkownikowi odczyt 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 dotyczące opublikowanych stron musi zawierać te same ograniczenia co reguły zabezpieczeń:
db.collection("stories").where("published", "==", true).get()
Ograniczenie zapytania .where("published", "==", true) gwarantuje, że resource.data.published to true w przypadku każdego wyniku. Dlatego to zapytanie spełnia reguły zabezpieczeń i może odczytywać dane.
Zapytania: OR
Podczas sprawdzania logicznego zapytania OR (or, in lub array-contains-any) pod kątem zestawu reguł, Reguły sprawdzają każdą wartość porównania osobno. Każda wartość porównania musi spełniać ograniczenia reguły zabezpieczeń. Na przykład w przypadku tej reguły:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
Nieprawidłowe: zapytanie nie gwarantuje, że x > 5 we wszystkich potencjalnych dokumentach
// 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])
)
Prawidłowe: 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ń
Reguły zabezpieczeń mogą też akceptować lub odrzucać zapytania na podstawie ich ograniczeń.
Zmienna request.query zawiera właściwości limit, offset i orderBy zapytania. Na przykład reguły zabezpieczeń mogą odrzucać zapytania, które nie ograniczają 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 te zmiany:
- Zbiór reguł rozdziela regułę odczytu na reguły dla
getilist. - Reguła
getogranicza pobieranie pojedynczych dokumentów do dokumentów publicznych lub dokumentów utworzonych przez użytkownika. - Reguła
liststosuje te same ograniczenia coget, ale w przypadku zapytań. Sprawdza też limit zapytań, a następnie odrzuca każde zapytanie bez limitu lub z limitem większym niż 10. - Zbiór 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 zabezpieczeń
Domyślnie zapytania są ograniczone do jednej kolekcji i pobierają wyniki tylko z niej. Za pomocą zapytań dotyczących grupy kolekcji możesz pobierać wyniki z grupy kolekcji składającej się ze wszystkich kolekcji o tym samym identyfikatorze. W tej sekcji opisano, jak zabezpieczyć zapytania dotyczące grupy kolekcji za pomocą reguł zabezpieczeń.
Zabezpieczanie dokumentów i wykonywanie zapytań na ich temat na podstawie grup kolekcji
W regułach zabezpieczeń musisz wyraźnie zezwolić na zapytania dotyczące grupy kolekcji, pisząc regułę dla grupy kolekcji:
- Upewnij się, że
rules_version = '2';jest pierwszym wierszem zestawu reguł. Zapytania dotyczące grup kolekcji wymagają nowego rekurencyjnego symbolu wieloznacznego{name=**}z reguł zabezpieczeń w wersji 2. - Napisz regułę dla grupy kolekcji za pomocą
match /{path=**}/[COLLECTION_ID]/{doc}.
Weźmy na przykład forum zorganizowane w forum dokumenty zawierające posts podkolekcje:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
W tej aplikacji posty mogą być edytowane przez ich właścicieli i odczytywane 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()
Co jednak, jeśli chcesz pokazać bieżącemu użytkownikowi jego posty na wszystkich forach?
Możesz użyć zapytania dotyczącego grupy kolekcji, aby pobrać wyniki ze wszystkich kolekcji posts:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
W regułach zabezpieczeń musisz zezwolić na to zapytanie, tworząc regułę odczytu lub wyświetlania 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 reguły będą stosowane do wszystkich kolekcji o identyfikatorze posts niezależnie od hierarchii. Te zasady dotyczą na przykład wszystkich tych kolekcji posts:
/posts/{postid}/forums/{forumid}/posts/{postid}/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Zabezpieczanie zapytań dotyczących grup kolekcji na podstawie pola
Podobnie jak zapytania dotyczące pojedynczej kolekcji, zapytania dotyczące grupy kolekcji muszą spełniać ograniczenia określone przez reguły zabezpieczeń. Możemy na przykład dodać pole published do każdego posta na forum, tak jak 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 na podstawie stanu published i posta author:
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 korzystający z przeglądarki, Apple i Androida mogą wysyłać te 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 ze wszystkich forów:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()Autorzy mogą pobrać wszystkie swoje opublikowane i nieopublikowane posty ze wszystkich forów:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Zabezpieczanie i wysyłanie zapytań o dokumenty na podstawie grupy kolekcji i ścieżki dokumentu
W niektórych przypadkach możesz ograniczyć zapytania dotyczące grupy kolekcji na podstawie ścieżki dokumentu. Aby utworzyć te ograniczenia, możesz użyć tych samych technik zabezpieczania i wysyłania zapytań o dokumenty 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. Mimo że wiemy, który użytkownik jest właścicielem dokumentu transaction, na podstawie ścieżki dokumentu, powielamy te informacje w każdym dokumencie transaction, ponieważ pozwala nam to na 2 rzeczy:
Zapisuj zapytania dotyczące grupy kolekcji, które są ograniczone do dokumentów zawierających określony element
/users/{userid}w ścieżce dokumentu. 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)Egzekwuj to ograniczenie w przypadku wszystkich zapytań w grupie kolekcji
transactions, aby jeden użytkownik nie mógł pobrać dokumentówtransactioninnego użytkownika.
Egzekwujemy to ograniczenie w naszych regułach zabezpieczeń 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
}
}
}
Dalsze kroki
- Bardziej szczegółowy przykład kontroli dostępu opartej na rolach znajdziesz w artykule Zabezpieczanie dostępu do danych dla użytkowników i grup.
- Zapoznaj się z dokumentacją reguł zabezpieczeń.