Warunki zapisu reguł zabezpieczeń Cloud Firestore

Ten przewodnik opiera się na przewodniku na temat tworzenia reguł zabezpieczeń i pokazuje, jak dodawać warunki do reguły Cloud Firestore Security Rules. Jeśli nie jesteś znasz podstawy usługi Cloud Firestore Security Rules, zobacz pierwsze kroki Google.

Podstawowym elementem składowym Cloud Firestore Security Rules jest warunek. Warunek to wyrażenie logiczne określające, czy dana operacja powinna zostać dozwolona, czy odrzucona. Za pomocą reguł zabezpieczeń możesz tworzyć warunki, które weryfikują uwierzytelnianie użytkownika, sprawdzają dane przychodzące lub nawet uzyskują dostęp do innych części Twojej bazy danych.

Uwierzytelnianie

Jednym z najczęstszych wzorów reguł zabezpieczeń jest kontrolowanie dostępu na podstawie stanu uwierzytelniania użytkownika. Na przykład aplikacja może zezwalać tylko na zalogowanych użytkowników w celu zapisywania danych:

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

Innym typowym wzorcem jest zapewnienie, aby użytkownicy mogli odczytywać i zapisywać tylko swoje dane:

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

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

Walidacja danych

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

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

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

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

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

Dostęp do innych dokumentów

Za pomocą funkcji get()exists() reguły zabezpieczeń mogą porównywać przychodzące żądania z innymi dokumentami w bazie danych. Funkcje get() i exists() oczekują pełnych ścieżek dokumentów. Jeśli używasz zmiennych do tworzenia ścieżek dla funkcji get()exists(), musisz jawnie ujęć zmienne w nawiasach kwadratowych za pomocą składni $(variable).

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

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

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

W przypadku zapisów możesz użyć funkcji getAfter(), aby uzyskać dostęp do stanu po zakończeniu transakcji lub partii zapisów, ale przed zatwierdzeń transakcyjnych lub wsadowych. Podobnie jak get(), funkcja getAfter() przyjmuje w pełni określoną ścieżkę dokumentu. Do definiowania zbiorów zapisów możesz użyć parametru getAfter() które muszą zostać zrealizowane łącznie jako transakcja lub wsad.

Dostęp do limitów połączeń

Obowiązuje limit wywołań dostępu do dokumentu na ocenę zestawu reguł:

  • 10 w przypadku żądań dotyczących pojedynczego dokumentu i zapytań.
  • 20 dla odczytu wielu dokumentów, transakcji i zbiorczego zapisu. Poprzedni limit 10 operacji obowiązuje również w przypadku każdej operacji.

    Wyobraź sobie na przykład, że tworzysz wsadowe żądanie zapisu z 3 zapisami oraz aby reguły zabezpieczeń używały 2 wywołań dostępu do dokumentu i weryfikować każdy zapis. W tym przypadku każde zapisywanie korzysta z 2 z 10 wywołań dostępu, a zbiórkowe żądanie zapisywania korzysta z 6 z 20 wywołań dostępu.

Przekroczenie dowolnego z limitów skutkuje błędem braku uprawnień. Niektóre wywołania dostępu do dokumentu mogą być przechowywane w pamięci podręcznej, a wywołania z pamięci podręcznej nie są wliczane do limitów.

Szczegółowe informacje o tym, jak te limity wpływają na transakcje i zbiorowe zapisy, znajdziesz w przewodniku Bezpieczeństwo operacji atomowych.

Dostęp do połączeń i cen

Użycie tych funkcji pozwala wykonać operację odczytu w bazie danych, co oznacza, że opłata za czytanie dokumentów jest naliczana nawet wtedy, gdy reguły zostaną odrzucone. do ich przesłania. Sprawdź cennik usługi Cloud Firestore bardziej szczegółowe informacje rozliczeniowe.

Funkcje niestandardowe

W miarę jak Twoje reguły zabezpieczeń stają się bardziej złożone, być może warto opakować zestawy warunków w funkcjach, których możesz używać ponownie w zestawie reguł. Reguły zabezpieczeń obsługują funkcje niestandardowe. Składnia funkcji niestandardowych jest podobna do JavaScriptu, ale funkcje reguł zabezpieczeń są napisane w języku specyficznym dla danej domeny, który ma kilka ważnych ograniczeń:

  • Funkcje mogą zawierać tylko jedno wyrażenie 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órych są zdefiniowane. Na przykład funkcja zdefiniowana w argumencie zakres 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ć. Łączna głębokość wywołania zasobnika jest ograniczona do 10.
  • W regułach w wersji v2 funkcje mogą definiować zmienne za pomocą słowa kluczowego let. Funkcje mogą mieć do 10 powiązań zezwalających, ale muszą kończyć się zwrotem .

Funkcja jest definiowana za pomocą słowa kluczowego function i przyjmuje od 0 do nieograniczonej liczby argumentów. Możesz na przykład połączyć 2 typy warunków użytych w przykładach powyżej w jednej funkcji:

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();
    }
  }
}

Korzystanie z funkcji w regułach bezpieczeństwa ułatwia ich utrzymanie, gdy ich złożoność rośnie.

Reguły nie są filtrami

Gdy zabezpieczysz dane i zaczniesz pisać zapytania, pamiętaj, że funkcje zabezpieczeń Reguły nie są filtrami. Nie można utworzyć zapytania dotyczącego wszystkich dokumentów w i oczekuje, że Cloud Firestore zwróci tylko dokumenty, bieżący klient ma uprawnienia dostępu.

Na przykład taka reguła zabezpieczeń:

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

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

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

Dozwolone: to reguła zezwalająca na to zapytanie, ponieważ klauzula where("visibility", "==", "public") gwarantuje, że zbiór wyników spełnia warunek reguły:

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

Cloud Firestore Reguły zabezpieczeń sprawdzają każde zapytanie pod kątem potencjalnego wyniku i odrzucają żądanie, jeśli może ono zwrócić dokument, którego klient nie ma uprawnień do odczytu. Zapytania muszą spełniać ograniczenia ustawione przez reguły zabezpieczeń. Więcej informacji o regułach zabezpieczeń i zapytaniach znajdziesz w artykule Bezpieczne zapytania o dane.

Dalsze kroki