Warunki zapisu reguł zabezpieczeń Cloud Firestore

Ten przewodnik stanowi uzupełnienie przewodnika po strukturyzacji reguł zabezpieczeń i pokazuje, jak dodawać warunki do Cloud Firestore Security Rules. Jeśli nie znasz podstaw Cloud Firestore Security Rules, zapoznaj się z przewodnikiem dla początkujących.

Podstawowym elementem składowym Cloud Firestore Security Rules jest warunek. Warunek to wyrażenie logiczne, które określa, czy dana operacja powinna być dozwolona czy odrzucona. Używaj reguł zabezpieczeń do pisania warunków, które sprawdzają uwierzytelnianie użytkowników, weryfikują przychodzące dane, a nawet uzyskują dostęp do innych części bazy danych.

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.

Uwierzytelnianie

Jednym z najczęstszych wzorców reguł zabezpieczeń jest kontrolowanie dostępu na podstawie stanu uwierzytelniania użytkownika. Na przykład aplikacja może zezwalać na zapisywanie danych tylko zalogowanym użytkownikom:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

Innym typowym wzorcem jest zapewnienie, że użytkownicy mogą odczytywać i zapisywać tylko własne dane:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

Jeśli Twoja aplikacja korzysta z Uwierzytelniania Firebase lub Google Cloud Identity Platform, zmienna request.auth zawiera informacje uwierzytelniające klienta, który żąda danych. Więcej informacji o request.auth znajdziesz w dokumentacji referencyjnej.

Walidacja danych

Wiele aplikacji przechowuje informacje o kontroli dostępu jako pola w dokumentach w bazie danych. Cloud Firestore Security Rules może dynamicznie zezwalać na dostęp lub go odmawiać na podstawie danych dokumentu:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Zmienna resource odnosi się do żądanego dokumentu, a resource.data to mapa wszystkich pól i wartości przechowywanych w dokumencie. Więcej informacji o zmiennej resource znajdziesz w dokumentacji referencyjnej.

Podczas zapisywania danych możesz porównać dane przychodzące z dotychczasowymi. W takim przypadku, jeśli zestaw reguł zezwala na oczekujący zapis, zmienna request.resource zawiera przyszły stan dokumentu. W przypadku operacji update, które modyfikują tylko podzbiór pól dokumentu, zmienna request.resource będzie zawierać stan dokumentu oczekującego po operacji. Możesz sprawdzić wartości pól w request.resource, aby zapobiec niechcianym lub niespójnym aktualizacjom danych:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

Uzyskiwanie dostępu do innych dokumentów

Za pomocą funkcji get() i exists() reguły zabezpieczeń mogą oceniać przychodzące żądania na podstawie innych dokumentów w bazie danych. Funkcje get() i exists() oczekują w pełni określonych ścieżek dokumentów. Jeśli używasz zmiennych do tworzenia ścieżek dla get() i exists(), musisz jawnie zmienić znaczenie zmiennych za pomocą składni $(variable).

W przykładzie poniżej zmienna database jest przechwytywana przez instrukcję dopasowania match /databases/{database}/documents i używana do utworzenia ścieżki:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid));

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
    }
  }
}

W przypadku operacji zapisu możesz użyć funkcji getAfter(), aby uzyskać dostęp do stanu dokumentu po zakończeniu transakcji lub zapisu wsadowego, ale przed zatwierdzeniem transakcji lub zapisu wsadowego. Podobnie jak get(), funkcja getAfter() przyjmuje w pełni określoną ścieżkę dokumentu. Za pomocą getAfter() możesz definiować zbiory operacji zapisu, które muszą być wykonywane razem jako transakcja lub grupa.

Limity dostępu do rozmów

Istnieje limit wywołań dostępu do dokumentu na ocenę zestawu reguł:

  • 10 w przypadku żądań dotyczących pojedynczego dokumentu i żądań zapytań.
  • 20 w przypadku odczytów wielu dokumentów, transakcji i zapisów wsadowych. Poprzedni limit wynoszący 10 również dotyczy każdej operacji.

    Załóżmy na przykład, że tworzysz żądanie zapisu zbiorczego z 3 operacjami zapisu, a reguły zabezpieczeń używają 2 wywołań dostępu do dokumentu, aby zweryfikować każdy zapis. W tym przypadku każdy zapis wykorzystuje 2 z 10 wywołań dostępu, a zbiorcze żądanie zapisu wykorzystuje 6 z 20 wywołań dostępu.

Przekroczenie któregoś z tych limitów spowoduje błąd braku uprawnień. Niektóre wywołania dostępu do dokumentów mogą być przechowywane w pamięci podręcznej, a wywołania z pamięci podręcznej nie są wliczane do limitów.

Szczegółowe informacje o tym, jak te limity wpływają na transakcje i zapisy zbiorcze, znajdziesz w przewodniku po zabezpieczaniu operacji niepodzielnych.

Połączenia z Access i ceny

Użycie tych funkcji powoduje wykonanie operacji odczytu w bazie danych, co oznacza, że zostanie naliczona opłata za odczyt dokumentów, nawet jeśli reguły odrzucą żądanie. Więcej informacji o rozliczeniach znajdziesz w artykule Ceny reguł.

Funkcje niestandardowe

W miarę jak reguły zabezpieczeń stają się coraz bardziej złożone, możesz opakowywać zestawy warunków w funkcje, których można używać wielokrotnie w całym zestawie reguł. Reguły zabezpieczeń obsługują funkcje niestandardowe. Składnia funkcji niestandardowych przypomina nieco JavaScript, ale funkcje reguł zabezpieczeń są pisane w języku specyficznym dla domeny, który ma pewne istotne ograniczenia:

  • Funkcje mogą zawierać tylko jedną instrukcję return. Nie mogą zawierać żadnej dodatkowej logiki. Nie mogą na przykład wykonywać pętli ani wywoływać usług zewnętrznych.
  • Funkcje mogą automatycznie uzyskiwać dostęp do funkcji i zmiennych z zakresu, w którym są zdefiniowane. Na przykład funkcja zdefiniowana w zakresie service cloud.firestore ma dostęp do zmiennej resource i funkcji wbudowanych, takich jak get() i exists().
  • Funkcje mogą wywoływać inne funkcje, ale nie mogą być rekurencyjne. Łączna głębokość stosu wywołań jest ograniczona do 10.
  • W regułach w wersji v2 funkcje mogą definiować zmienne za pomocą słowa kluczowego let. Funkcje mogą mieć maksymalnie 10 powiązań let, ale muszą kończyć się instrukcją powrotu.

Funkcja jest definiowana za pomocą słowa kluczowego function i przyjmuje co najmniej 0 argumentów. Możesz na przykład połączyć 2 typy warunków użytych w powyższych przykładach w jedną funkcję:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Używanie funkcji w regułach zabezpieczeń ułatwia ich utrzymanie w miarę wzrostu złożoności reguł.

Reguły to nie filtry

Gdy zabezpieczysz dane i zaczniesz pisać zapytania, pamiętaj, że reguły zabezpieczeń nie są filtrami. Nie możesz napisać zapytania dotyczącego wszystkich dokumentów w kolekcji i oczekiwać, że reguły zwrócą tylko te dokumenty, do których bieżący klient ma uprawnienia dostępu.

Weźmy na przykład tę regułę zabezpieczeń:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Odrzucono: ta reguła odrzuca to zapytanie, ponieważ zbiór wyników może zawierać dokumenty, w których visibility nie jest public:

Sieć
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

Dozwolone: ta reguła zezwala na następujące zapytanie, ponieważ klauzula where("visibility", "==", "public") gwarantuje, że zbiór wyników spełnia warunek reguły:

Sieć
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

Reguły zabezpieczeń sprawdzają każde zapytanie pod kątem potencjalnego wyniku i odrzucają żądanie, jeśli może ono zwrócić dokument, do którego klient nie ma uprawnień do odczytu. Zapytania muszą być zgodne z ograniczeniami określonymi w regułach zabezpieczeń. Więcej informacji o regułach i zapytaniach dotyczących zabezpieczeń znajdziesz w artykule o bezpiecznym wysyłaniu zapytań o dane.

Dalsze kroki