Ta strona opiera się na pojęciach opisanych w artykułach Struktura reguł zabezpieczeń i Pisanie warunków dla reguł zabezpieczeń, aby wyjaśnić, jak za pomocą Cloud Firestore Security Rules można tworzyć reguły, które pozwalają klientom wykonywać operacje na niektórych polach w dokumencie, ale nie na innych.
Czasami możesz chcieć kontrolować zmiany w dokumencie nie na poziomie dokumentu, ale na poziomie pola.
Możesz na przykład zezwolić klientowi na tworzenie lub zmienianie dokumentu, ale nie na edytowanie określonych pól w tym dokumencie. Możesz też wymagać, aby każdy dokument tworzony przez klienta zawierał określony zestaw pól. Z tego przewodnika dowiesz się, jak wykonać niektóre z tych zadań za pomocą Cloud Firestore Security Rules.
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.
Zezwalanie na dostęp do odczytu tylko w przypadku określonych pól
Odczyty w regułach są wykonywane na poziomie dokumentu. Możesz pobrać cały dokument lub nic. Nie ma możliwości pobrania części dokumentu. Nie można uniemożliwić użytkownikom odczytywania określonych pól w dokumencie, używając tylko reguł zabezpieczeń.
Jeśli w dokumencie są pewne pola, które chcesz ukryć przed niektórymi użytkownikami, najlepiej umieścić je w osobnym dokumencie. Możesz na przykład utworzyć dokument w podkolekcji private w ten sposób:
/employees/{emp_id}
name: "Alice Hamilton",
department: 461,
start_date: <timestamp>
/employees/{emp_id}/private/finances
salary: 80000,
bonus_mult: 1.25,
perf_review: 4.2
Następnie możesz dodać reguły zabezpieczeń, które mają różne poziomy dostępu do tych 2 kolekcji. W tym przykładzie używamy niestandardowych deklaracji uwierzytelniania, aby określić, że tylko użytkownicy z niestandardową deklaracją uwierzytelniania role równą Finance mogą wyświetlać informacje finansowe pracownika.
service cloud.firestore {
match /databases/{database}/documents {
// Allow any logged in user to view the public employee data
match /employees/{emp_id} {
allow read: if request.resource.auth != null
// Allow only users with the custom auth claim of "Finance" to view
// the employee's financial data
match /private/finances {
allow read: if request.resource.auth &&
request.resource.auth.token.role == 'Finance'
}
}
}
}
Ograniczanie pól podczas tworzenia dokumentu
Reguły nie mają schematu, co oznacza, że na poziomie bazy danych nie ma żadnych ograniczeń dotyczących pól, które zawiera dokument. Ta elastyczność może ułatwić programowanie, ale czasami możesz chcieć mieć pewność, że klienci mogą tworzyć tylko dokumenty zawierające określone pola lub niezawierające innych pól.
Możesz utworzyć te reguły, sprawdzając metodę keys obiektu request.resource.data. To jest lista wszystkich pól, które klient próbuje zapisać w tym nowym dokumencie. Łącząc ten zestaw pól z funkcjami takimi jak hasOnly() lub hasAny(), możesz dodać logikę, która ogranicza typy dokumentów, które użytkownik może dodawać do reguł.
Wymaganie określonych pól w nowych dokumentach
Załóżmy, że chcesz mieć pewność, że wszystkie dokumenty utworzone w kolekcji restaurant zawierają co najmniej pola name, location i city. Możesz to zrobić, wywołując hasAll() na liście kluczy w nowym dokumencie.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document contains a name
// location, and city field
match /restaurant/{restId} {
allow create: if request.resource.data.keys().hasAll(['name', 'location', 'city']);
}
}
}
Dzięki temu można tworzyć restauracje z innymi polami, ale wszystkie dokumenty utworzone przez klienta będą zawierać co najmniej te 3 pola.
Zabranianie określonych pól w nowych dokumentach
Podobnie możesz uniemożliwić klientom tworzenie dokumentów zawierających określone pola, używając hasAny() na liście zabronionych pól. Ta metoda zwraca wartość „true” (prawda), jeśli dokument zawiera którekolwiek z tych pól, więc prawdopodobnie chcesz zanegować wynik, aby zabronić używania określonych pól.
Na przykład w poniższym przykładzie klienci nie mogą utworzyć dokumentu zawierającego pole average_score lub rating_count, ponieważ te pola zostaną dodane później przez wywołanie serwera.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document does *not*
// contain an average_score or rating_count field.
match /restaurant/{restId} {
allow create: if (!request.resource.data.keys().hasAny(
['average_score', 'rating_count']));
}
}
}
Tworzenie listy dozwolonych pól dla nowych dokumentów
Zamiast zabraniać używania określonych pól w nowych dokumentach, możesz utworzyć listę tylko tych pól, które są wyraźnie dozwolone w nowych dokumentach. Następnie możesz użyć funkcji hasOnly(), aby upewnić się, że wszystkie nowo utworzone dokumenty zawierają tylko te pola (lub ich podzbiór) i żadne inne.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document doesn't contain
// any fields besides the ones listed below.
match /restaurant/{restId} {
allow create: if (request.resource.data.keys().hasOnly(
['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
Łączenie pól wymaganych i opcjonalnych
Możesz połączyć operacje hasAll i hasOnly w regułach zabezpieczeń, aby wymagać niektórych pól i zezwalać na inne. Na przykład w tym przypadku wszystkie nowe dokumenty muszą zawierać pola name, location i city, a opcjonalnie mogą zawierać pola address, hours i cuisine.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document has a name,
// location, and city field, and optionally address, hours, or cuisine field
match /restaurant/{restId} {
allow create: if (request.resource.data.keys().hasAll(['name', 'location', 'city'])) &&
(request.resource.data.keys().hasOnly(
['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
W rzeczywistym scenariuszu możesz przenieść tę logikę do funkcji pomocniczej, aby uniknąć powielania kodu i łatwiej połączyć pola opcjonalne i wymagane w jedną listę, na przykład w ten sposób:
service cloud.firestore {
match /databases/{database}/documents {
function verifyFields(required, optional) {
let allAllowedFields = required.concat(optional);
return request.resource.data.keys().hasAll(required) &&
request.resource.data.keys().hasOnly(allAllowedFields);
}
match /restaurant/{restId} {
allow create: if verifyFields(['name', 'location', 'city'],
['address', 'hours', 'cuisine']);
}
}
}
Ograniczanie pól podczas aktualizacji
Powszechną praktyką dotyczącą bezpieczeństwa jest zezwalanie klientom na edytowanie tylko niektórych pól. Nie można tego zrobić, patrząc wyłącznie na listę request.resource.data.keys() opisaną w poprzedniej sekcji, ponieważ ta lista reprezentuje cały dokument w postaci, jaką będzie miał po aktualizacji, i dlatego będzie zawierać pola, których klient nie zmienił.
Jeśli jednak użyjesz funkcji diff(), możesz porównać request.resource.data z obiektem resource.data, który reprezentuje dokument w bazie danych przed aktualizacją. Spowoduje to utworzenie obiektu mapDiff, który zawiera wszystkie zmiany między 2 różnymi mapami.
Wywołując metodę affectedKeys() na tym obiekcie mapDiff, możesz uzyskać zestaw pól, które zostały zmienione podczas edycji. Następnie możesz użyć funkcji takich jak hasOnly() lub hasAny(), aby upewnić się, że ten zestaw zawiera (lub nie zawiera) określone elementy.
Zapobieganie zmianom niektórych pól
Używając metody hasAny() na zbiorze wygenerowanym przez affectedKeys(), a następnie negując wynik, możesz odrzucić każde żądanie klienta, które próbuje zmienić pola, których nie chcesz zmieniać.
Możesz na przykład zezwolić klientom na aktualizowanie informacji o restauracji, ale nie na zmianę jej średniej oceny ani liczby opinii.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Allow the client to update a document only if that document doesn't
// change the average_score or rating_count fields
allow update: if (!request.resource.data.diff(resource.data).affectedKeys()
.hasAny(['average_score', 'rating_count']));
}
}
}
zezwalać na zmianę tylko niektórych pól,
Zamiast określać pola, których nie chcesz zmieniać, możesz też użyć funkcji hasOnly(), aby określić listę pól, które chcesz zmienić. Zwykle uważa się to za bezpieczniejsze, ponieważ zapisywanie w nowych polach dokumentu jest domyślnie niedozwolone, dopóki nie zezwolisz na to w regułach zabezpieczeń.
Na przykład zamiast blokować pola average_score i rating_count, możesz utworzyć reguły zabezpieczeń, które pozwolą klientom zmieniać tylko pola name, location, city, address, hours i cuisine.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Allow a client to update only these 6 fields in a document
allow update: if (request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
Oznacza to, że jeśli w przyszłej wersji aplikacji dokumenty restauracji będą zawierać pole telephone, próby edytowania tego pola nie powiodą się, dopóki nie dodasz go do listy hasOnly() w regułach zabezpieczeń.
Egzekwowanie typów pól
Innym skutkiem braku schematu w przypadku reguł jest brak egzekwowania na poziomie bazy danych typów danych, które mogą być przechowywane w określonych polach. Możesz to jednak wymusić w regułach zabezpieczeń za pomocą operatora is.
Na przykład ta reguła zabezpieczeń wymusza, aby pole score opinii było liczbą całkowitą, pola headline, content i author_name były ciągami znaków, a pole review_date było sygnaturą czasową.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Restaurant rules go here...
match /review/{reviewId} {
allow create: if (request.resource.data.score is int &&
request.resource.data.headline is string &&
request.resource.data.content is string &&
request.resource.data.author_name is string &&
request.resource.data.review_date is timestamp
);
}
}
}
}
Prawidłowe typy danych dla operatora is to bool, bytes, float, int, list, latlng, number, path, map, string i timestamp. Operator is obsługuje też typy danych constraint, duration, set i map_diff, ale ponieważ są one generowane przez sam język reguł zabezpieczeń, a nie przez klientów, rzadko używa się ich w większości praktycznych zastosowań.
Typy danych list i map nie obsługują typów ogólnych ani argumentów typu.
Innymi słowy, możesz użyć reguł zabezpieczeń, aby wymusić, że określone pole zawiera listę lub mapę, ale nie możesz wymusić, aby pole zawierało listę wszystkich liczb całkowitych lub wszystkich ciągów znaków.
Podobnie możesz używać reguł zabezpieczeń, aby wymuszać wartości typów dla konkretnych wpisów na liście lub mapie (odpowiednio za pomocą notacji nawiasów lub nazw kluczy), ale nie ma skrótu, który pozwalałby wymusić typy danych wszystkich elementów na mapie lub liście jednocześnie.
Na przykład te reguły zapewniają, że pole tags w dokumencie zawiera listę, a pierwszy wpis jest ciągiem znaków. Zapewnia też, że pole product zawiera mapę, która z kolei zawiera nazwę produktu będącą ciągiem znaków i ilość będącą liczbą całkowitą.
service cloud.firestore {
match /databases/{database}/documents {
match /orders/{orderId} {
allow create: if request.resource.data.tags is list &&
request.resource.data.tags[0] is string &&
request.resource.data.product is map &&
request.resource.data.product.name is string &&
request.resource.data.product.quantity is int
}
}
}
}
Typy pól muszą być egzekwowane zarówno podczas tworzenia, jak i aktualizowania dokumentu. Dlatego warto rozważyć utworzenie funkcji pomocniczej, którą można wywołać zarówno w sekcji tworzenia, jak i aktualizowania reguł zabezpieczeń.
service cloud.firestore {
match /databases/{database}/documents {
function reviewFieldsAreValidTypes(docData) {
return docData.score is int &&
docData.headline is string &&
docData.content is string &&
docData.author_name is string &&
docData.review_date is timestamp;
}
match /restaurant/{restId} {
// Restaurant rules go here...
match /review/{reviewId} {
allow create: if reviewFieldsAreValidTypes(request.resource.data) &&
// Other rules may go here
allow update: if reviewFieldsAreValidTypes(request.resource.data) &&
// Other rules may go here
}
}
}
}
Wymuszanie typów w polach opcjonalnych
Ważne jest, aby pamiętać, że wywołanie metody request.resource.data.foo w dokumencie, w którym nie istnieje foo, powoduje błąd, dlatego każda reguła zabezpieczeń, która wykonuje to wywołanie, odrzuci żądanie. Możesz poradzić sobie z tą sytuacją, używając metody get w request.resource.data. Metoda get umożliwia podanie domyślnego argumentu dla pola, które pobierasz z mapy, jeśli to pole nie istnieje.
Jeśli na przykład dokumenty do sprawdzenia zawierają też opcjonalne pole photo_url i opcjonalne pole tags, które chcesz zweryfikować jako ciągi znaków i listy, możesz to zrobić, przepisując funkcję reviewFieldsAreValidTypes w ten sposób:
function reviewFieldsAreValidTypes(docData) {
return docData.score is int &&
docData.headline is string &&
docData.content is string &&
docData.author_name is string &&
docData.review_date is timestamp &&
docData.get('photo_url', '') is string &&
docData.get('tags', []) is list;
}
Spowoduje to odrzucenie dokumentów, w których pole tags istnieje, ale nie jest listą, a jednocześnie zezwoli na dokumenty, które nie zawierają pola tags (lub photo_url).
Częściowe zapisy nigdy nie są dozwolone.
Ostatnia uwaga dotycząca Cloud Firestore Security Rules: pozwalają one klientowi na wprowadzenie zmiany w dokumencie lub odrzucają całą zmianę. Nie możesz utworzyć reguł zabezpieczeń, które akceptują zapisy w niektórych polach dokumentu, a odrzucają inne w ramach tej samej operacji.