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ł umożliwia tworzenie reguł pasujących do dowolnych elementów, od wszystkich zapisów w całej bazie danych po operacje na konkretnym dokumencie.

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

Deklaracja dotycząca usługi i bazy danych

Cloud Firestore Security Rules zawsze zaczynaj od tego oświadczenia:

service cloud.firestore {
  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 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. Obecnie każdy projekt ma tylko jedną bazę danych o nazwie (default).

Podstawowe reguły odczytu i zapisu

Reguły podstawowe składają się z instrukcji match określającej ścieżkę dokumentu i wyrażenia allow, które szczegółowo opisuje, kiedy można odczytać określone dane:

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 oświadczenia o dopasowaniu 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 dopasowania używa składni symbolu wieloznacznego {city}. Oznacza to, że reguła ma zastosowanie do każdego dokumentu w kolekcji cities, np. /cities/SF lub /cities/NYC. Gdy allow wyrażenia w instrukcji dopasowania zostaną obliczone, zmienna city zostanie przekształcona w nazwę dokumentu miasta, np. SF lub NYC.

.

Operacje szczegółowe

W niektórych sytuacjach warto podzielić operacje readwrite na bardziej szczegółowe. Na przykład aplikacja może wymagać innych warunków tworzenia dokumentów niż ich usuwania. Możesz też zezwolić na odczytywanie pojedynczych dokumentów, ale odrzucać duże zapytania.

Regułę read można podzielić na getlist, a regułę write – na create, updatedelete:

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ą podkolekcji. Ważne jest, aby zrozumieć, jak reguły zabezpieczeń działają w przypadku danych hierarchicznych.

Rozważ sytuację, w której każdy dokument w kolekcji cities zawiera podkolekcję landmarks. Reguły zabezpieczeń mają zastosowanie tylko do pasującej ścieżki, więc mechanizmy kontroli dostępu zdefiniowane w kolekcji cities nie mają zastosowania do podkolekcji landmarks. Zamiast tego napisz jawne reguły, aby kontrolować dostęp do podzbiorów:

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. Te zestawy reguł są zatem 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>;
    }
  }
}

Rekurencyjne symbole wieloznaczne

Jeśli chcesz, aby reguły miały zastosowanie do dowolnie głębokiej hierarchii, użyj rekursywnej składni symbolu wieloznacznego – {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 rekursywnej składni symbolu wieloznacznego, 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 podkolekcji. Na przykład reguły wymienione powyżej pasowałyby do dokumentu znajdującego się w lokalizacji /cities/SF/landmarks/coit_tower, a wartość zmiennej document wynosiłaby SF/landmarks/coit_tower.

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

Wersja 1

Reguły zabezpieczeń domyślnie korzystają z wersji 1. W wersji 1 rekursywne symbole wieloznaczne 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 cities kolekcji, natomiast match /cities/{document=**} pasuje do dokumentów w cities kolekcji i kolekcjach podrzędnych.

Rekursywne symbole wieloznaczne muszą znajdować się na końcu oświadczenia o dopasowaniu.

Wersja 2

W wersji 2 reguł bezpieczeństwa rekursywne symbole wieloznaczne pasują do zera lub większej liczby elementów ścieżki. Symbol match/cities/{city}/{document=**} pasuje do dokumentów w dowolnych podkolekcjach, a także do dokumentów w kolekcji match/cities/{city}/{document=**}.cities

Aby włączyć wersję 2, musisz dodać rules_version = '2'; na początku 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żdym wyrażeniu dopasowania możesz użyć maksymalnie jednego rekursywnego symbolu wieloznacznego, ale w wersji 2 możesz go umieścić w dowolnym miejscu wyrażenia dopasowania. 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ń dotyczących grup kolekcji, musisz używać wersji 2. Więcej informacji znajdziesz w artykule Zabezpieczanie zapytań dotyczących grup kolekcji.

Nakładające się instrukcje dopasowania

Dokument może pasować do więcej niż 1 match. Jeśli z żądaniem 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 operacje odczytu i zapisu w kolekcji cities będą dozwolone, ponieważ druga reguła zawsze ma wartość true, mimo że pierwsza reguła zawsze ma wartość false.

Limity reguł zabezpieczeń

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

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

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

Przekroczenie któregokolwiek z tych limitów spowoduje błąd dotyczący braku uprawnień.

Niektóre wywołania dostępu do dokumentów mogą być buforowane, a buforowane wywołania 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 instrukcji match 100
Maksymalna liczba zmiennych przechwytywania ścieżki dozwolonych w zagnieżdżonych instrukcjach match 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 rekurencyjnych lub cyklicznych wywołań funkcji 0 (niedozwolone)
Maksymalna liczba wyrażeń ocenianych w ramach jednego żądania 1000
Maksymalny rozmiar zestawu reguł Zestawy reguł muszą spełniać 2 limity rozmiaru:
  • limit 256 KB na rozmiar źródła tekstowego zestawu reguł opublikowanego w Firebase konsoli lub w interfejsie CLI za pomocą polecenia firebase deploy.
  • limit 250 KB na rozmiar skompilowanego zestawu reguł, który powstaje, gdy Firebase przetwarza źródło i aktywuje je na backendzie.

Dalsze kroki