了解 2023 年 Google I/O 大会上介绍的 Firebase 亮点。了解详情

Język reguł bezpieczeństwa

Reguły bezpieczeństwa Firebase wykorzystują elastyczne, wydajne, niestandardowe języki obsługujące szeroki zakres złożoności i szczegółowości. Reguły możesz określić jako szczegółowe lub ogólne, jeśli ma to sens w przypadku Twojej aplikacji. Reguły bazy danych czasu rzeczywistego używają składni przypominającej 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 języku CEL z match i allow , które obsługują warunkowy dostęp.

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

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

Podstawowa struktura

Cloud Firestore

Reguły bezpieczeństwa Firebase w Cloud Firestore i Cloud Storage mają 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órych działanie zezwalasz. Standardowe metody to: get , list , create , update i delete . Wygodne metody read i write umożliwiają szeroki dostęp do odczytu i zapisu w 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 ma ono wartość true.

Każde z tych pojęć jest opisane bardziej szczegółowo poniżej.

Magazyn w chmurze

Reguły bezpieczeństwa Firebase w Cloud Firestore i Cloud Storage mają 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órych działanie zezwalasz. Standardowe metody to: get , list , create , update i delete . Wygodne metody read i write umożliwiają szeroki dostęp do odczytu i zapisu w 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 ma ono wartość true.

Każde z tych pojęć jest opisane bardziej szczegółowo poniżej.

Baza danych czasu rzeczywistego

W bazie danych czasu rzeczywistego reguły bezpieczeństwa Firebase składają się z wyrażeń podobnych do języka 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>>
    }
  }
}

Reguła zawiera trzy podstawowe elementy:

  • Ścieżka: Lokalizacja bazy danych. Odzwierciedla to strukturę JSON Twojej bazy danych.
  • Żądanie: Są to metody używane przez regułę do udzielania dostępu. Reguły read i write zapewniają szeroki dostęp do odczytu i zapisu, podczas gdy reguły validate działają jako dodatkowa weryfikacja w celu przyznania dostępu na podstawie przychodzących lub istniejących danych.
  • Warunek: Warunek zezwalający na żądanie, jeśli ma ono wartość prawda.

Konstrukcje reguł

Cloud Firestore

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

  • Deklaracja service : Deklaruje produkt Firebase, do którego mają zastosowanie reguły.
  • Blok match : definiuje ścieżkę w bazie danych lub zasobniku pamięci masowej, do której mają zastosowanie reguły.
  • Instrukcja allow : zapewnia warunki udzielania dostępu, zróżnicowane według metod. Obsługiwane metody to: get , list , create , update , delete , a także 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 instrukcjami allow , które określają warunki przyznania dostępu do żądań. Zmienne request i resource są dostępne do użycia w warunkach reguły. Język Firebase Security Rules obsługuje również deklaracje function .

Wersja składni

Instrukcja syntax wskazuje wersję języka Firebase Rules użytego do zapisania ź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 silnika v1 .

Praca

Deklaracja service określa, do którego produktu lub usługi Firebase mają zastosowanie Twoje reguły. Do każdego pliku źródłowego można dołączyć tylko jedną deklarację service .

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 zarówno dla Cloud Firestore, jak i Cloud Storage za pomocą Firebase CLI, musisz przechowywać je w osobnych plikach.

Mecz

Blok match deklaruje wzorzec path , który jest dopasowany do ścieżki żądanej operacji (przychodzący request.path ). Treść match musi zawierać jeden lub więcej zagnieżdżonych bloków match , instrukcji allow lub deklaracji function . Ścieżka w zagnieżdżonych blokach match jest względna w stosunku do ścieżki w nadrzędnym bloku match .

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

Dopasowania do wzorca path mogą być częściowe lub kompletne:

  • Dopasowania częściowe: wzorzec path jest dopasowaniem prefiksu request.path .
  • Pełne dopasowania: path ścieżki pasuje do całego request.path .

Po uzyskaniu pełnego dopasowania oceniane są reguły w bloku. Po uzyskaniu częściowego dopasowania zagnieżdżone reguły match są testowane w celu sprawdzenia, czy jakakolwiek zagnieżdżona path zakończy dopasowanie.

Reguły w każdym pełnym match są oceniane w celu ustalenia, czy zezwolić na żądanie. Jeśli jakakolwiek pasująca reguła zapewnia dostęp, żądanie jest dozwolone. Jeśli żadna pasująca reguła nie zapewnia 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:

  • Jednosegmentowy symbol wieloznaczny: Zmienna wieloznaczna jest deklarowana w ścieżce przez zawijanie zmiennej w nawiasy klamrowe: {variable} . Ta zmienna jest dostępna w instrukcji match jako string .
  • Rekurencyjny symbol wieloznaczny: rekurencyjny lub wielosegmentowy symbol wieloznaczny dopasowuje wiele segmentów ścieżki na ścieżce lub poniżej. Ten symbol wieloznaczny pasuje do wszystkich ścieżek poniżej lokalizacji, w której go ustawiłeś. Możesz to zadeklarować, dodając ciąg znaków =** 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 rzeczywiste zasady. Reguły allow można zastosować do jednej lub kilku metod. Warunki w oświadczeniu allow muszą zostać ocenione jako prawdziwe, aby Cloud Firestore lub Cloud Storage mogły spełnić każde przychodzące żądanie. Możesz także pisać allow zezwalające bez warunków, na przykład allow read . Jeśli jednak instrukcja allow nie zawiera warunku, zawsze zezwala na żądanie dla tej metody.

Jeśli którakolwiek z reguł allow dla metody jest spełniona, żądanie jest dozwolone. Ponadto, jeśli szersza reguła zapewnia dostęp, Reguły przyznają dostęp i zignorują 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 odczytywać 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 ścieżce podrzędnej — 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 przyznaje dostęp żądaniom przychodzącym tej samej metody.

metoda Typ prośby
Wygodne metody
read Dowolny typ żądania odczytu
write Dowolny typ żądania zapisu
Standardowe metody
get Czytaj prośby o pojedyncze dokumenty lub pliki
list Odczytywanie żądań dotyczących zapytań i kolekcji
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ć metod odczytu w tym samym bloku match ani sprzecznych metod zapisu w tej samej deklaracji path .

Na przykład następujące zasady nie zadziałają:

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ć zawrzeć zestawy warunków w funkcjach, których będziesz mógł ponownie używać w swoim zestawie reguł. Reguły bezpieczeństwa obsługują funkcje niestandardowe. Składnia funkcji niestandardowych jest trochę podobna do języka JavaScript, ale funkcje reguł bezpieczeństwa są zapisywane w języku specyficznym dla domeny, który ma pewne ważne ograniczenia:

  • 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 zostały zdefiniowane. Na przykład funkcja zdefiniowana w zakresie service cloud.firestore ma dostęp do zmiennej resource i wbudowanych funkcji, takich jak get() i exists() .
  • Funkcje mogą wywoływać inne funkcje, ale nie mogą się powtarzać. 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 let powiązań, 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ż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();
    }
  }
}

Oto przykład pokazują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 kolekcji admins. Aby uzyskać leniwą ocenę bez konieczności niepotrzebnych wyszukiwań, skorzystaj z krótkiej natury && (AND) i || (OR) porównania, aby wywołać drugą funkcję tylko wtedy, gdy isAuthor ma wartość true (dla porównań && ) lub fałsz (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);
}

Korzystanie z funkcji w regułach bezpieczeństwa sprawia, że ​​są one łatwiejsze w utrzymaniu wraz ze wzrostem złożoności reguł.

Magazyn w chmurze

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

  • Deklaracja service : Deklaruje produkt Firebase, do którego mają zastosowanie reguły.
  • Blok match : definiuje ścieżkę w bazie danych lub zasobniku pamięci masowej, do której mają zastosowanie reguły.
  • Instrukcja allow : zapewnia warunki udzielania dostępu, zróżnicowane według metod. Obsługiwane metody to: get , list , create , update , delete , a także 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 instrukcjami allow , które określają warunki przyznania dostępu do żądań. Zmienne request i resource są dostępne do użycia w warunkach reguły. Język Firebase Security Rules obsługuje również deklaracje function .

Wersja składni

Instrukcja syntax wskazuje wersję języka Firebase Rules użytego do zapisania ź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 silnika v1 .

Praca

Deklaracja service określa, do którego produktu lub usługi Firebase mają zastosowanie Twoje reguły. Do każdego pliku źródłowego można dołączyć tylko jedną deklarację service .

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 zarówno dla Cloud Firestore, jak i Cloud Storage za pomocą Firebase CLI, musisz przechowywać je w osobnych plikach.

Mecz

Blok match deklaruje wzorzec path , który jest dopasowany do ścieżki żądanej operacji (przychodzący request.path ). Treść match musi zawierać jeden lub więcej zagnieżdżonych bloków match , instrukcji allow lub deklaracji function . Ścieżka w zagnieżdżonych blokach match jest względna w stosunku do ścieżki w nadrzędnym bloku match .

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

Dopasowania do wzorca path mogą być częściowe lub całkowite:

  • Dopasowania częściowe: wzorzec path jest dopasowaniem prefiksu request.path .
  • Pełne dopasowania: path ścieżki pasuje do całego request.path .

Po uzyskaniu pełnego dopasowania oceniane są reguły w bloku. Po uzyskaniu częściowego dopasowania zagnieżdżone reguły match są testowane w celu sprawdzenia, czy jakakolwiek zagnieżdżona path zakończy dopasowanie.

Reguły w każdym pełnym match są oceniane w celu ustalenia, czy zezwolić na żądanie. Jeśli jakakolwiek pasująca reguła zapewnia dostęp, żądanie jest dozwolone. Jeśli żadna pasująca reguła nie zapewnia 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:

  • Jednosegmentowy symbol wieloznaczny: Zmienna wieloznaczna jest deklarowana w ścieżce przez zawijanie zmiennej w nawiasy klamrowe: {variable} . Ta zmienna jest dostępna w instrukcji match jako string .
  • Rekurencyjny symbol wieloznaczny: rekurencyjny lub wielosegmentowy symbol wieloznaczny dopasowuje wiele segmentów ścieżki na ścieżce lub poniżej. Ten symbol wieloznaczny pasuje do wszystkich ścieżek poniżej lokalizacji, w której go ustawiłeś. Możesz to zadeklarować, dodając ciąg znaków =** 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 rzeczywiste zasady. Reguły allow można zastosować do jednej lub kilku metod. Warunki w oświadczeniu allow muszą zostać ocenione jako prawdziwe, aby Cloud Firestore lub Cloud Storage mogły spełnić każde przychodzące żądanie. Możesz także pisać allow zezwalające bez warunków, na przykład allow read . Jeśli jednak instrukcja allow nie zawiera warunku, zawsze zezwala na żądanie dla tej metody.

Jeśli którakolwiek z reguł allow dla metody jest spełniona, żądanie jest dozwolone. Ponadto, jeśli szersza reguła zapewnia dostęp, Reguły przyznają dostęp i zignorują 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 odczytywać 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 ścieżce podrzędnej — 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 przyznaje dostęp żądaniom przychodzącym tej samej metody.

metoda Typ prośby
Wygodne metody
read Dowolny typ żądania odczytu
write Dowolny typ żądania zapisu
Standardowe metody
get Czytaj prośby o pojedyncze dokumenty lub pliki
list Odczytywanie żądań dotyczących zapytań i kolekcji
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ć metod odczytu w tym samym bloku match ani sprzecznych metod zapisu w tej samej deklaracji path .

Na przykład następujące zasady nie zadziałają:

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ć zawrzeć zestawy warunków w funkcjach, których będziesz mógł ponownie używać w swoim zestawie reguł. Reguły bezpieczeństwa obsługują funkcje niestandardowe. Składnia funkcji niestandardowych jest trochę podobna do języka JavaScript, ale funkcje reguł bezpieczeństwa są zapisywane w języku specyficznym dla domeny, który ma pewne ważne ograniczenia:

  • 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 zostały zdefiniowane. Na przykład funkcja zdefiniowana w zakresie service cloud.firestore ma dostęp do zmiennej resource i wbudowanych funkcji, takich jak get() i exists() .
  • Funkcje mogą wywoływać inne funkcje, ale nie mogą się powtarzać. 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 let powiązań, 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ż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();
    }
  }
}

Oto przykład pokazują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 kolekcji admins. Aby uzyskać leniwą ocenę bez konieczności niepotrzebnych wyszukiwań, skorzystaj z krótkiej natury && (AND) i || (OR) porównania, aby wywołać drugą funkcję tylko wtedy, gdy isAuthor ma wartość true (dla porównań && ) lub fałsz (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);
}

Korzystanie z funkcji w regułach bezpieczeństwa sprawia, że ​​są one łatwiejsze w utrzymaniu wraz ze wzrostem złożoności reguł.

Baza danych czasu rzeczywistego

Jak opisano powyżej, Reguły Bazy Danych Czasu Rzeczywistego obejmują trzy podstawowe elementy: lokalizację bazy danych jako lustrzane odbicie struktury JSON bazy danych, typ żądania oraz warunek przyznający dostęp.

Lokalizacja bazy danych

Struktura Twoich reguł powinna być zgodna ze strukturą danych przechowywanych w Twojej bazie danych. Na przykład w aplikacji 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 przedrostka $ przed segmentem ścieżki, aby dopasować regułę do dowolnych 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 — mają zastosowanie do metody żądania przychodzącego. Typ reguły validate wymusza struktury danych oraz weryfikuje format i zawartość danych. Reguły uruchamiają reguły .validate po sprawdzeniu, czy reguła .write zapewnia dostęp.

Typy reguł
.Czytać Opisuje, czy i kiedy dane mogą być odczytywane przez użytkowników.
.pisać Opisuje, czy i kiedy dane mogą być zapisywane.
.uprawomocnić Definiuje, jak będzie wyglądać prawidłowo sformatowana wartość, czy ma atrybuty podrzędne i typ danych.

Domyślnie, jeśli nie ma reguły, która na to zezwala, dostęp w ścieżce jest zabroniony.

Warunki zabudowy

Cloud Firestore

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

request żądania

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

request.auth

JSON Web Token (JWT), który zawiera dane uwierzytelniające z Firebase Authentication. auth token zawiera zestaw standardowych oświadczeń i wszelkich niestandardowych oświadczeń tworzonych za pomocą uwierzytelniania Firebase. Dowiedz się więcej o regułach bezpieczeństwa i uwierzytelnianiu Firebase .

request.method

request.method może być dowolną metodą standardową lub metodą niestandardową. Istnieją również wygodne metody read i write , które upraszczają zasady pisania, które mają zastosowanie odpowiednio do wszystkich standardowych metod tylko do odczytu lub wszystkich standardowych metod tylko do zapisu.

request.params

request.params obejmują wszelkie dane niezwiązane konkretnie z request.resource , które mogą być przydatne do oceny. W praktyce ta mapa powinna być pusta dla wszystkich metod standardowych i powinna zawierać dane inne niż zasoby dla metod niestandardowych. Usługi muszą uważać, aby nie zmieniać nazw 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 inne niż bezpieczne w adresie 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łanie resource w warunku spowoduje co najwyżej jeden odczyt wartości z usługi. To wyszukiwanie będzie wliczane do limitu 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

Skorzystaj z 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 i indeks i .

Operator Opis Asocjatywność
a[i] a() af Indeks, połączenie, dostęp do pola od lewej do prawej
!a -a Jednoargumentowa negacja od prawej do lewej
a/ba%ba*b Operatory multiplikatywne od lewej do prawej
a+b ab Operatory addytywne od lewej do prawej
a>ba>=ba Operatorzy relacyjni od lewej do prawej
a in b Istnienie na liście lub mapie od lewej do prawej
a is type Porównanie typów, gdzie type może być bool, int, float, number, string, list, map, timestamp, duration, path lub latlng od lewej do prawej
a==ba!=b Operatory porównania od lewej do prawej
a && b Warunkowe I od lewej do prawej
a || b Warunkowe LUB od lewej do prawej
a ? true_value : false_value Wyrażenie trójskładnikowe od lewej do prawej

Magazyn w chmurze

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

request żądania

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

request.auth

JSON Web Token (JWT), który zawiera dane uwierzytelniające z Firebase Authentication. auth token zawiera zestaw standardowych oświadczeń i wszelkich niestandardowych oświadczeń tworzonych za pomocą uwierzytelniania Firebase. Dowiedz się więcej o regułach bezpieczeństwa i uwierzytelnianiu Firebase .

request.method

request.method może być dowolną metodą standardową lub metodą niestandardową. Istnieją również wygodne metody read i write , które upraszczają zasady pisania, które mają zastosowanie odpowiednio do wszystkich standardowych metod tylko do odczytu lub wszystkich standardowych metod tylko do zapisu.

request.params

request.params obejmują wszelkie dane niezwiązane konkretnie z request.resource , które mogą być przydatne do oceny. W praktyce ta mapa powinna być pusta dla wszystkich metod standardowych i powinna zawierać dane inne niż zasoby dla metod niestandardowych. Usługi muszą uważać, aby nie zmieniać nazw 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 inne niż bezpieczne w adresie 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łanie resource w warunku spowoduje co najwyżej jeden odczyt wartości z usługi. To wyszukiwanie będzie wliczane do limitu 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

Skorzystaj z 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 i indeks i .

Operator Opis Asocjatywność
a[i] a() af Indeks, połączenie, dostęp do pola od lewej do prawej
!a -a Jednoargumentowa negacja od prawej do lewej
a/ba%ba*b Operatory multiplikatywne od lewej do prawej
a+b ab Operatory addytywne od lewej do prawej
a>ba>=ba Operatorzy relacyjni od lewej do prawej
a in b Istnienie na liście lub mapie od lewej do prawej
a is type Porównanie typów, gdzie type może być bool, int, float, number, string, list, map, timestamp, duration, path lub latlng od lewej do prawej
a==ba!=b Operatory porównania od lewej do prawej
a && b Warunkowe I od lewej do prawej
a || b Warunkowe LUB od lewej do prawej
a ? true_value : false_value Wyrażenie trójskładnikowe od lewej do prawej

Baza danych czasu rzeczywistego

Warunek to wyrażenie logiczne określające, czy dana operacja powinna być dozwolona, ​​czy zabroniona. Możesz zdefiniować te warunki w Regułach bazy danych czasu rzeczywistego w następujący sposób.

Wstępnie zdefiniowane zmienne

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

Predefiniowane zmienne
Teraz Bieżący czas w milisekundach od ery Linuksa. Działa to szczególnie dobrze w przypadku sprawdzania poprawności znaczników czasu utworzonych za pomocą pliku firebase.database.ServerValue.TIMESTAMP pakietu SDK.
źródło RuleDataSnapshot reprezentujący ścieżkę główną w bazie danych Firebase, jaka istniała przed próbą wykonania operacji.
nowe dane RuleDataSnapshot reprezentujący dane, które istniałyby po próbie wykonania operacji. Obejmuje zapisywane nowe dane i istniejące dane.
dane RuleDataSnapshot reprezentujący dane, które istniały przed próbą wykonania operacji.
$ zmienne Ścieżka wieloznaczna używana do reprezentowania identyfikatorów i dynamicznych kluczy podrzędnych.
autoryzacja Reprezentuje ładunek tokenu uwierzytelnionego użytkownika.

Tych zmiennych można używać w dowolnym miejscu reguł. Na przykład poniższe reguły bezpieczeństwa zapewniają, że dane zapisywane w węźle /foo/ muszą być łańcuchem 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"
    }
  }
}

Reguły oparte na danych

Dowolne dane z Twojej bazy danych mogą być użyte w Twoich regułach. Używając wstępnie zdefiniowanych 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ł readOnly , aw nowo zapisanych danych występuje 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 swoich 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 używa reguł bezpieczeństwa opartych na użytkownikach i reguł opartych na zapytaniach, aby ograniczyć dostęp do danych w kolekcji baskets tylko do koszyków zakupów, których właścicielem jest aktywny użytkownik:

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

Następująca kwerenda, która zawiera parametry kwerendy w regule, powiedzie 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 także użyć reguł opartych na zapytaniach, aby ograniczyć ilość danych pobieranych przez klienta w ramach 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)

Poniższe query. wyrażenia są dostępne w regułach bezpieczeństwa bazy danych czasu rzeczywistego.

Wyrażenia reguł oparte na zapytaniach
Wyrażenie Typ Opis
zapytanie.kolejnośćWedług klucza
zapytanie.kolejnośćWgPriorytetu
zapytanie.kolejnośćWedługWartości
logiczna Prawda dla zapytań uporządkowanych według klucza, priorytetu lub wartości. Fałsz inaczej.
zapytanie.zamówienieWgDziecka strunowy
zero
Użyj ciągu, aby przedstawić ścieżkę względną 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ść jest równa null.
zapytanie.startAt
zapytanie.endAt
zapytanie.równaTo
strunowy
numer
logiczna
zero
Pobiera granice wykonywanego zapytania lub zwraca wartość null, jeśli nie ma zestawu powiązań.
zapytanie.limitDoPierwszego
zapytanie.limitToLast
numer
zero
Pobiera limit dla wykonywanego zapytania lub zwraca wartość null, jeśli nie ma ustawionego 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ą ogromną elastyczność, dzięki czemu reguły aplikacji mogą być tak proste lub tak złożone, jak tego potrzebujesz.

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