Tworzenie struktury reguł zabezpieczeń Cloud Firestore

Cloud Firestore Security Rules umożliwiają kontrolowanie dostępu do dokumentów i kolekcji w bazie danych. Elastyczna składnia reguł pozwala tworzyć reguły, które pasują do wszystkiego – od wszystkich zapisów w całej bazie danych po operacje na konkretnym dokumencie.

W tym przewodniku opisujemy podstawową składnię i strukturę reguł zabezpieczeń. Połącz tę składnię z warunkami reguł zabezpieczeń, aby utworzyć kompletne zestawy reguł.

Deklaracja usługi i bazy danych

Cloud Firestore Security Rules zawsze zaczynają się od tej deklaracji:

service cloud.firestore {
  // The {database} wildcard allows the rules to reference any database,
  // but these rules are only active on databases where they are explicitly deployed.
  match /databases/{database}/documents {
    // ...
  }
}

Deklaracja service cloud.firestore ogranicza zakres reguł do Cloud Firestore, co zapobiega konfliktom między Cloud Firestore Security Rules a regułami dotyczącymi innych usług, takich jak Cloud Storage.

Deklaracja match /databases/{database}/documents określa, że reguły powinny pasować do dowolnej bazy danych Cloud Firestore w projekcie. Projekt może zawierać maksymalnie 100 baz danych, ale tylko pierwsza utworzona baza danych jest oznaczona jako domyślna.

Cloud Firestore Security Rules są stosowane oddzielnie do każdej nazwanej bazy danych w projekcie. Oznacza to, że jeśli utworzysz kilka baz danych, musisz zarządzać regułami i wdrażać je oddzielnie dla każdej z nich. Szczegółowe instrukcje wdrażania aktualizacji znajdziesz w artykule Wdrażanie aktualizacji.

Podstawowe reguły odczytu i zapisu

Podstawowe reguły składają się z instrukcji match określającej ścieżkę dokumentu oraz wyrażenia allow określającego, kiedy dozwolony jest odczyt określonych danych:

service cloud.firestore {
  match /databases/{database}/documents {

    // Match any document in the 'cities' collection
    match /cities/{city} {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

Wszystkie instrukcje match powinny wskazywać dokumenty, a nie kolekcje. Instrukcja match może wskazywać konkretny dokument, np. match /cities/SF, lub używać symboli wieloznacznych, aby wskazywać dowolny dokument w określonej ścieżce, np. match /cities/{city}.

W powyższym przykładzie instrukcja match używa składni symbolu wieloznacznego {city}. Oznacza to, że reguła ma zastosowanie do dowolnego dokumentu w kolekcji cities, np. /cities/SF lub /cities/NYC. Gdy wyrażenia allow w instrukcji match są oceniane, zmienna city jest rozwiązywana na nazwę dokumentu miasta, np. SF lub NYC.

Operacje szczegółowe

W niektórych sytuacjach warto podzielić operacje read i write na bardziej szczegółowe operacje. Na przykład aplikacja może wymagać stosowania innych warunków podczas tworzenia dokumentu niż podczas jego usuwania. Możesz też zezwolić na odczyt pojedynczych dokumentów, ale zabronić wykonywania dużych zapytań.

Regułę read można podzielić na get i list, a regułę write na create, update i delete:

service cloud.firestore {
  match /databases/{database}/documents {
    // A read rule can be divided into get and list rules

    match /cities/{city} {
      // Applies to single document read requests
      allow get: if <condition>;

      // Applies to queries and collection read requests
      allow list: if <condition>;
    }
    // A write rule can be divided into create, update, and delete rules
    match /cities/{city} {
      // Applies to writes to nonexistent documents
      allow create: if <condition>;

      // Applies to writes to existing documents
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
}

Dane hierarchiczne

Dane w Cloud Firestore są uporządkowane w kolekcje dokumentów, a każdy dokument może rozszerzać hierarchię za pomocą kolekcji podrzędnych. Ważne jest, aby zrozumieć, jak reguły zabezpieczeń współdziałają z danymi hierarchicznymi.

Załóżmy, że każdy dokument w kolekcji cities zawiera kolekcję podrzędną landmarks. Reguły zabezpieczeń mają zastosowanie tylko do pasującej ścieżki, więc kontrola dostępu zdefiniowana w kolekcji cities nie ma zastosowania do kolekcji podrzędnej landmarks. Zamiast tego napisz wyraźne reguły, aby kontrolować dostęp do kolekcji podrzędnych:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

        // Explicitly define rules for the 'landmarks' subcollection
        match /landmarks/{landmark} {
          allow read, write: if <condition>;
        }
    }
  }
}

Podczas zagnieżdżania instrukcji match ścieżka wewnętrznej instrukcji match jest zawsze względna w stosunku do ścieżki zewnętrznej instrukcji match. Dlatego te zestawy reguł są równoważne:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

Symbole wieloznaczne rekurencyjne

Jeśli chcesz, aby reguły miały zastosowanie do dowolnie głębokiej hierarchii, użyj składni symbolu wieloznacznego rekurencyjnego {name=**}. Przykład:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

Gdy używasz składni symbolu wieloznacznego rekurencyjnego, zmienna symbolu wieloznacznego będzie zawierać cały pasujący segment ścieżki, nawet jeśli dokument znajduje się w głęboko zagnieżdżonej kolekcji podrzędnej. Na przykład reguły wymienione powyżej będą pasować do dokumentu znajdującego się w lokalizacji /cities/SF/landmarks/coit_tower, a wartość zmiennej document będzie równa SF/landmarks/coit_tower.

Pamiętaj jednak, że działanie symboli wieloznacznych rekurencyjnych zależy od wersji reguł.

Wersja 1

Reguły zabezpieczeń domyślnie używają wersji 1. W wersji 1 symbole wieloznaczne rekurencyjne pasują do co najmniej 1 elementu ścieżki. Nie pasują do pustej ścieżki, więc match /cities/{city}/{document=**} pasuje do dokumentów w kolekcjach podrzędnych, ale nie w kolekcji cities, natomiast match /cities/{document=**} pasuje zarówno do dokumentów w kolekcji cities, jak i w kolekcjach podrzędnych.

Symbole wieloznaczne rekurencyjne muszą znajdować się na końcu instrukcji match.

Wersja 2

W wersji 2 reguł zabezpieczeń symbole wieloznaczne rekurencyjne pasują do zera lub większej liczby elementów ścieżki. match/cities/{city}/{document=**} pasuje do dokumentów w dowolnych kolekcjach podrzędnych oraz do dokumentów w kolekcji cities.

Aby włączyć wersję 2, dodaj rules_version = '2'; u góry reguł zabezpieczeń:

rules_version = '2';
service cloud.firestore {
 match /databases/{database}/documents {
   // Matches any document in the cities collection as well as any document
   // in a subcollection.
   match /cities/{city}/{document=**} {
     allow read, write: if <condition>;
   }
 }
}

W każdej instrukcji match możesz mieć co najwyżej 1 symbol wieloznaczny rekurencyjny, ale w wersji 2 możesz umieścić go w dowolnym miejscu instrukcji match. Przykład:

rules_version = '2';
service cloud.firestore {
 match /databases/{database}/documents {
   // Matches any document in the songs collection group
   match /{path=**}/songs/{song} {
     allow read, write: if <condition>;
   }
 }
}

Jeśli używasz zapytań do grup kolekcji, musisz użyć wersji 2. Więcej informacji znajdziesz w artykule Zabezpieczanie zapytań do grup kolekcji.

Nakładające się instrukcje match

Dokument może pasować do więcej niż 1 instrukcji match. Jeśli do żądania pasuje kilka wyrażeń allow, dostęp jest dozwolony, jeśli którykolwiek z warunków jest true:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

W powyższym przykładzie wszystkie odczyty i zapisy w kolekcji cities będą dozwolone, ponieważ druga reguła jest zawsze true, nawet jeśli pierwsza reguła jest zawsze false.

Limity reguł zabezpieczeń

Podczas pracy z regułami zabezpieczeń pamiętaj o tych limitach:

Limit Szczegóły
Maksymalna liczba wywołań exists(), get() i getAfter() na żądanie
  • 10 w przypadku żądań dotyczących pojedynczych dokumentów i żądań zapytań.
  • 20 w przypadku odczytów wielu dokumentów, transakcji, i zapisów zbiorczych. Poprzedni limit 10 dotyczy też każdej operacji.

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

Przekroczenie któregokolwiek z tych limitów powoduje błąd odmowy uprawnień.

Niektóre wywołania dostępu do dokumentu mogą być buforowane, a wywołania buforowane nie są wliczane do limitów.

Maksymalna głębokość zagnieżdżenia instrukcji match 10
Maksymalna długość ścieżki w segmentach ścieżki dozwolona w zbiorze zagnieżdżonych match instrukcji 100
Maksymalna liczba zmiennych przechwytywania ścieżki dozwolona w zbiorze zagnieżdżonych match instrukcji 20
Maksymalna głębokość wywołania funkcji 20
Maksymalna liczba argumentów funkcji 7
Maksymalna liczba powiązań zmiennych let na funkcję 10
Maksymalna liczba wywołań funkcji rekurencyjnych lub cyklicznych 0 (niedozwolone)
Maksymalna liczba wyrażeń ocenianych na żądanie 1000
Maksymalny rozmiar zestawu reguł Zestawy reguł muszą spełniać 2 limity rozmiaru:
  • Limit 256 KB na rozmiar tekstu źródłowego zestawu reguł opublikowanego w konsoli Firebase lub w interfejsie wiersza poleceń za pomocą firebase deploy.
  • Limit 250 KB na rozmiar skompilowanego zestawu reguł, który powstaje gdy Firebase przetwarza źródło i aktywuje je w backendzie.

Dalsze kroki