Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Język reguł bezpieczeństwa

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Reguły zabezpieczeń Firebase wykorzystują elastyczne, zaawansowane, niestandardowe języki, które obsługują szeroki zakres złożoności i szczegółowości. Możesz ustawić swoje Reguły tak szczegółowe lub tak ogólne, jak ma to sens dla Twojej aplikacji. Reguły bazy danych czasu rzeczywistego używają składni, która wygląda jak JavaScript w strukturze JSON. Reguły Cloud Firestore i Cloud Storage używają języka opartego na języku Common Expression Language (CEL) , który opiera się na CEL z match i allow instrukcje, które obsługują warunkowo przyznany dostęp.

Ponieważ są to języki niestandardowe, istnieje jednak krzywa uczenia się. Skorzystaj z tego przewodnika, aby lepiej zrozumieć język reguł, gdy zagłębisz się w bardziej złożone reguły.

Wybierz produkt, aby dowiedzieć się więcej o jego zasadach.

Podstawowa struktura

Cloud Firestore

Reguły zabezpieczeń Firebase w Cloud Firestore i Cloud Storage wykorzystują następującą strukturę i składnię:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Podczas tworzenia reguł ważne jest zrozumienie następujących kluczowych pojęć:

  • Żądanie: metoda lub metody wywołane w instrukcji allow . To są metody, na które pozwalasz. Standardowe metody to: get , list , create , update i delete . Wygodne metody read i write umożliwiają szeroki dostęp do odczytu i zapisu na określonej ścieżce bazy danych lub magazynu.
  • Ścieżka: baza danych lub lokalizacja magazynu, reprezentowana jako ścieżka URI.
  • Reguła: instrukcja allow , która zawiera warunek zezwalający na żądanie, jeśli jego wartość jest prawdziwa.

Każda z tych koncepcji została szczegółowo opisana poniżej.

Magazyn w chmurze

Reguły zabezpieczeń Firebase w Cloud Firestore i Cloud Storage wykorzystują następującą strukturę i składnię:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Podczas tworzenia reguł ważne jest zrozumienie następujących kluczowych pojęć:

  • Żądanie: metoda lub metody wywołane w instrukcji allow . To są metody, na które pozwalasz. Standardowe metody to: get , list , create , update i delete . Wygodne metody read i write umożliwiają szeroki dostęp do odczytu i zapisu na określonej ścieżce bazy danych lub magazynu.
  • Ścieżka: baza danych lub lokalizacja magazynu, reprezentowana jako ścieżka URI.
  • Reguła: instrukcja allow , która zawiera warunek zezwalający na żądanie, jeśli jego wartość jest prawdziwa.

Każda z tych koncepcji została szczegółowo opisana poniżej.

Baza danych czasu rzeczywistego

W Bazie danych czasu rzeczywistego reguły zabezpieczeń Firebase składają się z wyrażeń podobnych do JavaScript zawartych w dokumencie JSON.

Używają następującej składni:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

W regule są trzy podstawowe elementy:

  • Ścieżka: lokalizacja bazy danych. To odzwierciedla strukturę JSON bazy danych.
  • Żądanie: są to metody, których używa reguła do przyznania dostępu. Reguły read i write zapewniają szeroki dostęp do odczytu i zapisu, podczas gdy reguły validate działają jako wtórna weryfikacja w celu przyznania dostępu na podstawie danych przychodzących lub istniejących.
  • Warunek: warunek, który zezwala na żądanie, jeśli jego ocena ma wartość prawda.

Konstrukcje reguł

Cloud Firestore

Podstawowe elementy reguły w Cloud Firestore i Cloud Storage to:

  • Deklaracja service : Deklaruje produkt Firebase, którego dotyczą reguły.
  • Blok match : definiuje ścieżkę w bazie danych lub zasobniku pamięci, do którego odnoszą się reguły.
  • Instrukcja allow : udostępnia warunki przyznawania dostępu, zróżnicowane według metod. Obsługiwane metody obejmują: get , list , create , update , delete oraz wygodne metody read i write .
  • Opcjonalne deklaracje function : zapewniają możliwość łączenia i zawijania warunków do użycia w wielu regułach.

service zawiera jeden lub więcej bloków match z oświadczeniami allow , które zapewniają warunki przyznające dostęp do żądań. Zmienne request i resource są dostępne do użycia w warunkach reguły. Język reguł zabezpieczeń Firebase obsługuje również deklaracje function .

Wersja składni

Instrukcja syntax wskazuje wersję języka reguł Firebase użytego do napisania źródła. Najnowsza wersja języka to v2 .

rules_version = '2';
service cloud.firestore {
...
}

Jeśli nie podano instrukcji rules_version , Twoje reguły zostaną ocenione przy użyciu aparatu v1 .

Usługa

Deklaracja service określa, do którego produktu lub usługi Firebase mają zastosowanie Twoje reguły. Możesz dołączyć tylko jedną deklarację service na plik źródłowy.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Magazyn w chmurze

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Jeśli definiujesz reguły dla Cloud Firestore i Cloud Storage za pomocą interfejsu wiersza polecenia Firebase, musisz przechowywać je w osobnych plikach.

Mecz

Blok match deklaruje wzorzec path , który jest dopasowywany do ścieżki żądanej operacji (żądanie request.path ). Treść match musi zawierać co najmniej jeden zagnieżdżony blok match , instrukcje allow lub deklaracje function . Ścieżka w zagnieżdżonych blokach match jest względna do ścieżki w nadrzędnym bloku match .

Wzorzec path to nazwa podobna do katalogu, która może zawierać zmienne lub symbole wieloznaczne. Wzór path umożliwia dopasowanie segmentu jednościeżkowego i wielościeżkowego. Wszystkie zmienne powiązane ze path są widoczne w zakresie match lub dowolnym zakresie zagnieżdżonym, w którym zadeklarowana jest path .

Dopasowania do wzorca path mogą być częściowe lub pełne:

  • Częściowe dopasowania: wzorzec path jest dopasowaniem przedrostka request.path .
  • Pełne dopasowania: wzorzec path pasuje do całego request.path .

Po wykonaniu kompletnego dopasowania, zasady w obrębie bloku są oceniane. Po dokonaniu częściowego dopasowania reguły match zagnieżdżonego są testowane, aby sprawdzić, czy jakakolwiek zagnieżdżona path zakończy dopasowanie.

Reguły w każdym pełnym match są oceniane w celu określenia, czy zezwolić na żądanie. Jeśli jakakolwiek pasująca reguła przyznaje dostęp, żądanie jest dozwolone. Jeśli żadna pasująca reguła nie udziela dostępu, żądanie jest odrzucane.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Jak pokazuje powyższy przykład, deklaracje path obsługują następujące zmienne:

  • Symbol wieloznaczny jednosegmentowy: zmienna wieloznaczna jest zadeklarowana w ścieżce przez zawinięcie zmiennej w nawiasy klamrowe: {variable} . Ta zmienna jest dostępna w instrukcji match jako string .
  • Rekurencyjny symbol wieloznaczny: rekurencyjny lub wielosegmentowy symbol wieloznaczny pasuje do wielu segmentów ścieżki na ścieżce lub poniżej. Ten symbol wieloznaczny pasuje do wszystkich ścieżek poniżej lokalizacji, w której został ustawiony. Możesz to zadeklarować, dodając ciąg =** na końcu zmiennej segmentu: {variable=**} . Ta zmienna jest dostępna w instrukcji match jako obiekt path .

Umożliwić

Blok match zawiera jedną lub więcej instrukcji allow . To są twoje aktualne zasady. Reguły allow można zastosować do jednej lub kilku metod. Warunki w instrukcji allow muszą mieć wartość true, aby Cloud Firestore lub Cloud Storage mógł spełnić każde przychodzące żądanie. Możesz także pisać instrukcje allow bez warunków, na przykład allow read . Jeśli jednak instrukcja allow nie zawiera warunku, zawsze zezwala na żądanie tej metody.

Jeśli którakolwiek z reguł allow dla metody jest spełniona, żądanie jest dozwolone. Ponadto, jeśli szersza reguła przyznaje dostęp, reguły przyznają dostęp i ignorują wszelkie bardziej szczegółowe reguły, które mogą ograniczać dostęp.

Rozważmy następujący przykład, w którym każdy użytkownik może czytać lub usuwać dowolne własne pliki. Bardziej szczegółowa reguła zezwala na zapisy tylko wtedy, gdy użytkownik żądający zapisu jest właścicielem pliku, a plik jest plikiem PNG. Użytkownik może usunąć dowolne pliki w podścieżce — nawet jeśli nie są to pliki PNG — ponieważ pozwala na to wcześniejsza reguła.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

metoda

Każda instrukcja allow zawiera metodę, która zapewnia dostęp dla żądań przychodzących tej samej metody.

metoda Typ prośby
Wygodne metody
read Dowolny rodzaj żądania odczytu
write Dowolny rodzaj żądania zapisu
Metody standardowe
get Przeczytaj prośby o pojedyncze dokumenty lub pliki
list Przeczytaj prośby o zapytania i kolekcje
create Napisz nowe dokumenty lub pliki
update Zapisz do istniejących dokumentów bazy danych lub zaktualizuj metadane pliku
delete Usunąć dane

Nie można nakładać się na metody odczytu w tym samym bloku match lub sprzeczne metody zapisu w tej samej deklaracji path .

Na przykład zawiodłyby następujące reguły:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Funkcjonować

W miarę jak twoje reguły bezpieczeństwa stają się coraz bardziej złożone, możesz chcieć otoczyć zestawy warunków funkcjami, które możesz ponownie wykorzystać w swoim zestawie reguł. Reguły bezpieczeństwa obsługują funkcje niestandardowe. Składnia funkcji niestandardowych przypomina trochę JavaScript, ale funkcje reguł bezpieczeństwa są napisane w języku specyficznym dla domeny, który ma kilka ważnych ograniczeń:

  • Funkcje mogą zawierać tylko jedną instrukcję return . Nie mogą zawierać żadnej dodatkowej logiki. Na przykład nie mogą 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ą rekursywnie. Całkowita głębokość stosu wywołań jest ograniczona do 20.
  • W regułach w wersji v2 funkcje mogą definiować zmienne za pomocą słowa kluczowego let . Funkcje mogą mieć do 10 powiązań let, ale muszą kończyć się instrukcją return.

Funkcja jest definiowana za pomocą słowa kluczowego function i przyjmuje zero lub więcej argumentów. Na przykład możesz chcieć połączyć dwa typy warunków użyte 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();
    }
  }
}

Oto przykład przedstawiający argumenty funkcji i przypisania let. Niech instrukcje przypisania muszą być oddzielone średnikami.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Zwróć uwagę, jak przypisanie isAdmin wymusza wyszukiwanie w kolekcji administratorów. W przypadku leniwej oceny bez konieczności zbędnych wyszukiwań skorzystaj ze zwartego charakteru && (AND) oraz || (LUB) w celu wywołania drugiej funkcji tylko wtedy, gdy isAuthor okaże się prawdą (dla porównań && ) lub fałszem (dla porównań || ).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

Używanie funkcji w regułach bezpieczeństwa sprawia, że ​​są one łatwiejsze do utrzymania w miarę wzrostu złożoności reguł.

Magazyn w chmurze

Podstawowe elementy reguły w Cloud Firestore i Cloud Storage to:

  • Deklaracja service : Deklaruje produkt Firebase, którego dotyczą reguły.
  • Blok match : definiuje ścieżkę w bazie danych lub zasobniku pamięci, do którego odnoszą się reguły.
  • Instrukcja allow : udostępnia warunki przyznawania dostępu, zróżnicowane według metod. Obsługiwane metody obejmują: get , list , create , update , delete oraz wygodne metody read i write .
  • Opcjonalne deklaracje function : zapewniają możliwość łączenia i zawijania warunków do użycia w wielu regułach.

service zawiera jeden lub więcej bloków match z oświadczeniami allow , które zapewniają warunki przyznające dostęp do żądań. Zmienne request i resource są dostępne do użycia w warunkach reguły. Język reguł zabezpieczeń Firebase obsługuje również deklaracje function .

Wersja składni

Instrukcja syntax wskazuje wersję języka reguł Firebase użytego do napisania źródła. Najnowsza wersja języka to v2 .

rules_version = '2';
service cloud.firestore {
...
}

Jeśli nie podano instrukcji rules_version , Twoje reguły zostaną ocenione przy użyciu aparatu v1 .

Usługa

Deklaracja service określa, do którego produktu lub usługi Firebase mają zastosowanie Twoje reguły. Możesz dołączyć tylko jedną deklarację service na plik źródłowy.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Magazyn w chmurze

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Jeśli definiujesz reguły dla Cloud Firestore i Cloud Storage za pomocą interfejsu wiersza polecenia Firebase, musisz przechowywać je w osobnych plikach.

Mecz

Blok match deklaruje wzorzec path , który jest dopasowywany do ścieżki żądanej operacji (żądanie request.path ). Treść match musi zawierać co najmniej jeden zagnieżdżony blok match , instrukcje allow lub deklaracje function . Ścieżka w zagnieżdżonych blokach match jest względna do ścieżki w nadrzędnym bloku match .

Wzorzec path to nazwa podobna do katalogu, która może zawierać zmienne lub symbole wieloznaczne. Wzór path umożliwia dopasowanie segmentu jednościeżkowego i wielościeżkowego. Wszystkie zmienne powiązane ze path są widoczne w zakresie match lub dowolnym zakresie zagnieżdżonym, w którym zadeklarowana jest path .

Dopasowania do wzorca path mogą być częściowe lub pełne:

  • Częściowe dopasowania: wzorzec path jest dopasowaniem przedrostka request.path .
  • Pełne dopasowania: wzorzec path pasuje do całego request.path .

Po wykonaniu kompletnego dopasowania, zasady w obrębie bloku są oceniane. Po dokonaniu częściowego dopasowania reguły match zagnieżdżonego są testowane, aby sprawdzić, czy jakakolwiek zagnieżdżona path zakończy dopasowanie.

Reguły w każdym pełnym match są oceniane w celu określenia, czy zezwolić na żądanie. Jeśli jakakolwiek pasująca reguła przyznaje dostęp, żądanie jest dozwolone. Jeśli żadna pasująca reguła nie udziela dostępu, żądanie jest odrzucane.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Jak pokazuje powyższy przykład, deklaracje path obsługują następujące zmienne:

  • Symbol wieloznaczny jednosegmentowy: zmienna wieloznaczna jest zadeklarowana w ścieżce przez zawinięcie zmiennej w nawiasy klamrowe: {variable} . Ta zmienna jest dostępna w instrukcji match jako string .
  • Rekurencyjny symbol wieloznaczny: rekurencyjny lub wielosegmentowy symbol wieloznaczny pasuje do wielu segmentów ścieżki na ścieżce lub poniżej. Ten symbol wieloznaczny pasuje do wszystkich ścieżek poniżej lokalizacji, w której został ustawiony. Możesz to zadeklarować, dodając ciąg =** na końcu zmiennej segmentu: {variable=**} . Ta zmienna jest dostępna w instrukcji match jako obiekt path .

Umożliwić

Blok match zawiera jedną lub więcej instrukcji allow . To są twoje aktualne zasady. Reguły allow można zastosować do jednej lub kilku metod. Warunki w instrukcji allow muszą mieć wartość true, aby Cloud Firestore lub Cloud Storage mógł spełnić każde przychodzące żądanie. Możesz także pisać instrukcje allow bez warunków, na przykład allow read . Jeśli jednak instrukcja allow nie zawiera warunku, zawsze zezwala na żądanie tej metody.

Jeśli którakolwiek z reguł allow dla metody jest spełniona, żądanie jest dozwolone. Ponadto, jeśli szersza reguła przyznaje dostęp, reguły przyznają dostęp i ignorują wszelkie bardziej szczegółowe reguły, które mogą ograniczać dostęp.

Rozważmy następujący przykład, w którym każdy użytkownik może czytać lub usuwać dowolne własne pliki. Bardziej szczegółowa reguła zezwala na zapisy tylko wtedy, gdy użytkownik żądający zapisu jest właścicielem pliku, a plik jest plikiem PNG. Użytkownik może usunąć dowolne pliki w podścieżce — nawet jeśli nie są to pliki PNG — ponieważ pozwala na to wcześniejsza reguła.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

metoda

Każda instrukcja allow zawiera metodę, która zapewnia dostęp dla żądań przychodzących tej samej metody.

metoda Typ prośby
Wygodne metody
read Dowolny rodzaj żądania odczytu
write Dowolny rodzaj żądania zapisu
Metody standardowe
get Przeczytaj prośby o pojedyncze dokumenty lub pliki
list Przeczytaj prośby o zapytania i kolekcje
create Napisz nowe dokumenty lub pliki
update Zapisz do istniejących dokumentów bazy danych lub zaktualizuj metadane pliku
delete Usunąć dane

Nie można nakładać się na metody odczytu w tym samym bloku match lub sprzeczne metody zapisu w tej samej deklaracji path .

Na przykład zawiodłyby następujące reguły:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Funkcjonować

W miarę jak twoje reguły bezpieczeństwa stają się coraz bardziej złożone, możesz chcieć otoczyć zestawy warunków funkcjami, które możesz ponownie wykorzystać w swoim zestawie reguł. Reguły bezpieczeństwa obsługują funkcje niestandardowe. Składnia funkcji niestandardowych przypomina trochę JavaScript, ale funkcje reguł bezpieczeństwa są napisane w języku specyficznym dla domeny, który ma kilka ważnych ograniczeń:

  • Funkcje mogą zawierać tylko jedną instrukcję return . Nie mogą zawierać żadnej dodatkowej logiki. Na przykład nie mogą 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ą rekursywnie. Całkowita głębokość stosu wywołań jest ograniczona do 20.
  • W regułach w wersji v2 funkcje mogą definiować zmienne za pomocą słowa kluczowego let . Funkcje mogą mieć do 10 powiązań let, ale muszą kończyć się instrukcją return.

Funkcja jest definiowana za pomocą słowa kluczowego function i przyjmuje zero lub więcej argumentów. Na przykład możesz chcieć połączyć dwa typy warunków użyte 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();
    }
  }
}

Oto przykład przedstawiający argumenty funkcji i przypisania let. Niech instrukcje przypisania muszą być oddzielone średnikami.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Zwróć uwagę, jak przypisanie isAdmin wymusza wyszukiwanie w kolekcji administratorów. W przypadku leniwej oceny bez konieczności zbędnych wyszukiwań skorzystaj ze zwartego charakteru && (AND) oraz || (LUB) w celu wywołania drugiej funkcji tylko wtedy, gdy isAuthor okaże się prawdą (dla porównań && ) lub fałszem (dla porównań || ).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

Używanie funkcji w regułach bezpieczeństwa sprawia, że ​​są one łatwiejsze do utrzymania w miarę wzrostu złożoności reguł.

Baza danych czasu rzeczywistego

Jak wspomniano powyżej, reguły bazy danych czasu rzeczywistego obejmują trzy podstawowe elementy: lokalizację bazy danych jako odzwierciedlenie struktury JSON bazy danych, typ żądania i warunek przyznający dostęp.

Lokalizacja bazy danych

Struktura Twoich reguł powinna być zgodna ze strukturą danych, które przechowujesz w swojej bazie danych. Na przykład w aplikacji do czatu z listą wiadomości możesz mieć dane, które wyglądają tak:

  {
    "messages": {
      "message0": {
        "content": "Hello",
        "timestamp": 1405704370369
      },
      "message1": {
        "content": "Goodbye",
        "timestamp": 1405704395231
      },
      ...
    }
  }

Twoje zasady powinny odzwierciedlać tę strukturę. Na przykład:

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

Jak pokazuje powyższy przykład, reguły bazy danych czasu rzeczywistego obsługują zmienną $location w celu dopasowania segmentów ścieżki. Użyj prefiksu $ przed segmentem ścieżki, aby dopasować regułę do wszystkich węzłów podrzędnych na ścieżce.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

Możesz także użyć $variable równolegle ze stałymi nazwami ścieżek.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

metoda

W Bazie danych czasu rzeczywistego istnieją trzy typy reguł. Dwa z tych typów reguł — read i write — dotyczą metody przychodzącego żądania. Reguła validate wymusza struktury danych oraz weryfikuje format i zawartość danych. Reguły uruchamiają reguły .validate po sprawdzeniu, czy reguła .write przyznaje dostęp.

Typy reguł
.czytać Opisuje, czy i kiedy użytkownicy mogą odczytywać dane.
.pisać Opisuje, czy i kiedy można zapisywać dane.
.uprawomocnić Definiuje, jak będzie wyglądać poprawnie sformatowana wartość, czy ma atrybuty podrzędne i typ danych.

Domyślnie, jeśli nie ma reguły zezwalającej na to, dostęp na ścieżce jest odmawiany.

Warunki zabudowy

Cloud Firestore

Warunek to wyrażenie logiczne, które określa, czy dana operacja powinna być dozwolona, ​​czy zabroniona. Zmienne request i resource zapewniają kontekst dla tych warunków.

Zmienna request

Zmienna request zawiera następujące pola i odpowiednie informacje:

request.auth

Token sieciowy JSON (JWT), który zawiera poświadczenia uwierzytelniania z uwierzytelniania Firebase. Token auth zawiera zestaw oświadczeń standardowych i wszelkich oświadczeń niestandardowych utworzonych za pomocą Uwierzytelniania Firebase. Dowiedz się więcej o regułach zabezpieczeń Firebase i uwierzytelnianiu .

request.method

Metoda request.method może być dowolną metodą standardową lub metodą niestandardową. Istnieją również wygodne metody read i write , aby uprościć reguły zapisu, które mają zastosowanie odpowiednio do wszystkich standardowych metod tylko do odczytu lub tylko do zapisu.

request.params

request.params zawierają wszelkie dane niezwiązane konkretnie z request.resource , które mogą być przydatne do oceny. W praktyce mapa ta powinna być pusta dla wszystkich metod standardowych i powinna zawierać dane niezasobowe dla metod niestandardowych. Usługi muszą uważać, aby nie zmieniać nazwy ani nie modyfikować typu żadnego z kluczy i wartości prezentowanych jako parametry.

request.path

request.path to ścieżka do resource docelowego . Ścieżka jest względna do usługi. Segmenty ścieżki zawierające znaki, które nie są bezpieczne dla adresu URL, takie jak / , są zakodowane w adresie URL.

Zmienna resource

resource to bieżąca wartość w usłudze reprezentowana jako mapa par klucz-wartość. Odwoływanie się do resource w warunku spowoduje co najwyżej jeden odczyt wartości z usługi. To wyszukiwanie będzie wliczane do przydziału związanego z usługą dla zasobu. W przypadku żądań get resource będzie wliczany do limitu tylko w przypadku odmowy.

Operatory i pierwszeństwo operatorów

Użyj poniższej tabeli jako odniesienia dla operatorów i ich odpowiedniego pierwszeństwa w regułach dla Cloud Firestore i Cloud Storage.

Biorąc pod uwagę dowolne wyrażenia a i b , pole f oraz indeks i .

Operator Opis Łączność
a[i] a() af Indeks, połączenie, dostęp do pola z lewej na prawą
!a -a Negacja jednoargumentowa od prawej do lewej
a/ba%ba*b Operatory multiplikatywne z lewej na prawą
a+b ab Operatory addytywne z lewej na prawą
a>ba>=ba Operatorzy relacyjni z lewej na prawą
a in b Istnienie na liście lub mapie z lewej na prawą
a is type Porównanie typów, gdzie type może być bool, int, float, number, string, lista, mapa, znacznik czasu, czas trwania, ścieżka lub latlng z lewej na prawą
a==ba!=b Operatory porównania z lewej na prawą
a && b Warunkowe AND z lewej na prawą
a || b Warunkowe OR z lewej na prawą
a ? true_value : false_value Wyrażenie trójczłonowe z lewej na prawą

Magazyn w chmurze

Warunek to wyrażenie logiczne, które określa, czy dana operacja powinna być dozwolona, ​​czy zabroniona. Zmienne request i resource zapewniają kontekst dla tych warunków.

Zmienna request

Zmienna request zawiera następujące pola i odpowiednie informacje:

request.auth

Token sieciowy JSON (JWT), który zawiera poświadczenia uwierzytelniania z uwierzytelniania Firebase. Token auth zawiera zestaw oświadczeń standardowych i wszelkich oświadczeń niestandardowych utworzonych za pomocą Uwierzytelniania Firebase. Dowiedz się więcej o regułach zabezpieczeń Firebase i uwierzytelnianiu .

request.method

Metoda request.method może być dowolną metodą standardową lub metodą niestandardową. Istnieją również wygodne metody read i write , aby uprościć reguły zapisu, które mają zastosowanie odpowiednio do wszystkich standardowych metod tylko do odczytu lub tylko do zapisu.

request.params

request.params zawierają wszelkie dane niezwiązane konkretnie z request.resource , które mogą być przydatne do oceny. W praktyce mapa ta powinna być pusta dla wszystkich metod standardowych i powinna zawierać dane niezasobowe dla metod niestandardowych. Usługi muszą uważać, aby nie zmieniać nazwy ani nie modyfikować typu żadnego z kluczy i wartości prezentowanych jako parametry.

request.path

request.path to ścieżka do resource docelowego . Ścieżka jest względna do usługi. Segmenty ścieżki zawierające znaki, które nie są bezpieczne dla adresu URL, takie jak / , są zakodowane w adresie URL.

Zmienna resource

resource to bieżąca wartość w usłudze reprezentowana jako mapa par klucz-wartość. Odwoływanie się do resource w warunku spowoduje co najwyżej jeden odczyt wartości z usługi. To wyszukiwanie będzie wliczane do przydziału związanego z usługą dla zasobu. W przypadku żądań get resource będzie wliczany do limitu tylko w przypadku odmowy.

Operatory i pierwszeństwo operatorów

Użyj poniższej tabeli jako odniesienia dla operatorów i ich odpowiedniego pierwszeństwa w regułach dla Cloud Firestore i Cloud Storage.

Biorąc pod uwagę dowolne wyrażenia a i b , pole f oraz indeks i .

Operator Opis Łączność
a[i] a() af Indeks, połączenie, dostęp do pola z lewej na prawą
!a -a Negacja jednoargumentowa od prawej do lewej
a/ba%ba*b Operatory multiplikatywne z lewej na prawą
a+b ab Operatory addytywne z lewej na prawą
a>ba>=ba Operatorzy relacyjni z lewej na prawą
a in b Istnienie na liście lub mapie z lewej na prawą
a is type Porównanie typów, gdzie type może być bool, int, float, number, string, lista, mapa, znacznik czasu, czas trwania, ścieżka lub latlng z lewej na prawą
a==ba!=b Operatory porównania z lewej na prawą
a && b Warunkowe AND z lewej na prawą
a || b Warunkowe OR z lewej na prawą
a ? true_value : false_value Wyrażenie trójczłonowe z lewej na prawą

Baza danych czasu rzeczywistego

Warunek to wyrażenie logiczne, które określa, czy dana operacja powinna być dozwolona, ​​czy zabroniona. Warunki te można zdefiniować w Regułach bazy danych czasu rzeczywistego w następujący sposób.

Wstępnie zdefiniowane zmienne

Istnieje wiele pomocnych, predefiniowanych zmiennych, do których można uzyskać dostęp w definicji reguły. Oto krótkie podsumowanie każdego z nich:

Wstępnie zdefiniowane zmienne
Teraz Aktualny czas w milisekundach od epoki Linuksa. Działa to szczególnie dobrze w przypadku walidacji sygnatur czasowych utworzonych za pomocą pakietu SDK firebase.database.ServerValue.TIMESTAMP.
źródło RuleDataSnapshot reprezentujący ścieżkę główną w bazie danych Firebase istniejącą przed próbą wykonania operacji.
nowe dane RuleDataSnapshot reprezentujący dane, które istniałyby po próbie wykonania operacji. Obejmuje nowe zapisywane dane i istniejące dane.
dane RuleDataSnapshot reprezentujący dane istniejące przed próbą wykonania operacji.
$ zmienne Ścieżka z symbolami wieloznacznymi używana do reprezentowania identyfikatorów i dynamicznych kluczy podrzędnych.
autoryzować Reprezentuje ładunek tokena uwierzytelnionego użytkownika.

Zmiennych tych można używać w dowolnym miejscu w regułach. Na przykład poniższe reguły bezpieczeństwa zapewniają, że dane zapisywane w węźle /foo/ muszą być ciągiem krótszym niż 100 znaków:

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

Zasady oparte na danych

Dowolne dane w Twojej bazie danych mogą być użyte w Twoich regułach. Używając predefiniowanych zmiennych root , data i newData , możesz uzyskać dostęp do dowolnej ścieżki, tak jak istniałaby przed lub po zdarzeniu zapisu.

Rozważmy ten przykład, który zezwala na operacje zapisu, o ile wartość węzła /allow_writes/ jest true , węzeł nadrzędny nie ma ustawionej flagi readOnly , a w nowo napisanych danych znajduje się element potomny o nazwie foo :

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

Reguły oparte na zapytaniach

Chociaż nie możesz używać reguł jako filtrów, możesz ograniczyć dostęp do podzbiorów danych, używając parametrów zapytania w swoich regułach. Użyj query. wyrażenia w regułach, aby przyznać dostęp do odczytu lub zapisu na podstawie parametrów zapytania.

Na przykład poniższa reguła oparta na zapytaniach wykorzystuje reguły zabezpieczeń oparte na użytkownikach i reguły oparte na zapytaniach w celu ograniczenia dostępu do danych w kolekcji baskets tylko do koszyków zakupów, które posiada aktywny użytkownik:

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

Następujące zapytanie, które zawiera parametry zapytania w regule, powiodłoby się:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

Jednak zapytania, które nie zawierają parametrów w regule, zakończą się niepowodzeniem z błędem PermissionDenied :

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

Możesz również użyć reguł opartych na zapytaniach, aby ograniczyć ilość danych pobieranych przez klienta za pomocą operacji odczytu.

Na przykład poniższa reguła ogranicza dostęp do odczytu tylko do pierwszych 1000 wyników zapytania, uporządkowanych według priorytetu:

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

Następujące query. wyrażenia są dostępne w regułach bazy danych czasu rzeczywistego.

Wyrażenia reguł oparte na zapytaniach
Wyrażenie Rodzaj Opis
zapytanie.zamówienieByKey
zapytanie.orderByPriority
zapytanie.orderByValue
logiczne Prawda dla zapytań uporządkowanych według klucza, priorytetu lub wartości. W przeciwnym razie fałsz.
zapytanie.orderByChild strunowy
zero
Użyj ciągu do reprezentowania ścieżki względnej do węzła podrzędnego. Na przykład query.orderByChild === "address/zip" . Jeśli zapytanie nie jest uporządkowane przez węzeł podrzędny, ta wartość ma wartość null.
zapytanie.startAt
zapytanie.endAt
zapytanie.equalTo
strunowy
numer
logiczne
zero
Pobiera granice wykonywanego zapytania lub zwraca wartość null, jeśli nie ma zestawu ograniczeń.
zapytanie.limitToFirst
zapytanie.limitToLast
numer
zero
Pobiera limit wykonywanego zapytania lub zwraca wartość null, jeśli nie ustawiono limitu.

Operatorzy

Reguły bazy danych czasu rzeczywistego obsługują wiele operatorów , których można użyć do łączenia zmiennych w instrukcji warunku. Zobacz pełną listę operatorów w dokumentacji referencyjnej .

Tworzenie warunków

Twoje rzeczywiste warunki będą się różnić w zależności od dostępu, który chcesz przyznać. Reguły celowo oferują ogromny stopień elastyczności, więc reguły Twojej aplikacji mogą być ostatecznie tak proste lub złożone, jak tego potrzebujesz.

Aby uzyskać wskazówki dotyczące tworzenia prostych, gotowych do produkcji reguł, zobacz Podstawowe reguły zabezpieczeń .