Testowanie reguł zabezpieczeń Cloud Firestore

Podczas tworzenia aplikacji możesz zablokować dostęp do swojego Baza danych Cloud Firestore. Jednak przed wdrożeniem potrzebnych jest zgłębianie szczegółów Reguły zabezpieczeń Cloud Firestore. Oprócz tworzenia prototypów dzięki emulatorowi Cloud Firestore oraz testowanie ogólnych funkcji i działania aplikacji, możesz pisać testy jednostkowe, które sprawdzają działanie reguł zabezpieczeń Cloud Firestore.

Krótkie wprowadzenie

Kilka podstawowych zastosowań testowych z prostymi regułami znajdziesz w krótkim wprowadzeniu.

Omówienie reguł zabezpieczeń Cloud Firestore

wdrożyć Uwierzytelnianie Firebase. Reguły zabezpieczeń Cloud Firestore dotyczące usług bezserwerowych uwierzytelniania, autoryzacji i weryfikacji danych podczas korzystania bibliotek klienta internetowego.

Reguły zabezpieczeń Cloud Firestore składają się z 2 części:

  1. Instrukcja match identyfikująca dokumenty w bazie danych.
  2. Wyrażenie allow kontrolujące dostęp do tych dokumentów.

Uwierzytelnianie Firebase weryfikuje użytkowników danych logowania i stanowi podstawę systemów dostępu opartych na użytkownikach i rolach.

Każde żądanie bazy danych z biblioteki klienta mobilnego/internetowego Cloud Firestore jest oceniane pod kątem Twoich reguł zabezpieczeń przed odczytaniem lub zapisem danych. Jeśli reguły odmawiają dostępu do dowolnej ze wskazanych ścieżek dokumentów, cała sekwencja nie powiodło się.

Więcej informacji o regułach zabezpieczeń Cloud Firestore znajdziesz w artykule Pierwsze kroki z regułami zabezpieczeń Cloud Firestore.

Zainstaluj emulator

Aby zainstalować emulator Cloud Firestore, użyj interfejsu wiersza poleceń Firebase. i uruchom to polecenie:

firebase setup:emulators:firestore

Uruchamianie emulatora

Zacznij od zainicjowania projektu Firebase w katalogu roboczym. To jest często jest to pierwszy krok podczas korzystania z interfejsu wiersza poleceń Firebase.

firebase init

Uruchom emulator za pomocą tego polecenia. Emulator będzie działać do zakończenia procesu:

firebase emulators:start --only firestore

W wielu przypadkach chcesz uruchomić emulator, uruchomić pakiet testowy, a potem wyłączyć wyłączyć emulator po przeprowadzeniu testów. Możesz to łatwo zrobić za pomocą Polecenie emulators:exec:

firebase emulators:exec --only firestore "./my-test-script.sh"

Po uruchomieniu emulator będzie próbował uruchomić się na porcie domyślnym (8080). Dostępne opcje zmień port emulatora, modyfikując sekcję "emulators" swojego Plik firebase.json:

{
  // ...
  "emulators": {
    "firestore": {
      "port": "YOUR_PORT"
    }
  }
}

Zanim uruchomisz emulator

Zanim zaczniesz korzystać z emulatora, pamiętaj o tych kwestiach:

  • Emulator początkowo wczyta reguły określone w polu firestore.rules pliku firebase.json. Oczekuje ona nazwy lokalny plik zawierający reguły zabezpieczeń Cloud Firestore i stosuje te reguły do wszystkich w projektach AI. Jeśli nie podasz lokalnej ścieżki pliku lub użyjesz loadFirestoreRules, zgodnie z opisem poniżej, emulator traktuje wszystkie projektów z otwartymi regułami.
  • Choć większość pakietów SDK Firebase obsługuje bezpośrednio emulatory, tylko biblioteka @firebase/rules-unit-testing obsługuje naśmiewanie się z auth w regułach zabezpieczeń, co znacznie ułatwia testowanie jednostkowe. Ponadto obsługuje kilka funkcji emulatorów, takich jak czyszczenie wszystkich danych, jak opisano poniżej.
  • Emulatory będą też akceptować produkcyjne tokeny uwierzytelniania Firebase udostępnione za pomocą pakietów SDK klienta i odpowiednio oceniać reguły, co umożliwia bezpośrednio do emulatorów w ramach testów integracji i testów ręcznych.

Przeprowadzanie lokalnych testów jednostkowych

Przeprowadzanie lokalnych testów jednostkowych za pomocą pakietu SDK JavaScript w wersji 9

Firebase rozpowszechnia bibliotekę testowania jednostkowego reguł zabezpieczeń wraz z jej wersją SDK 9 JavaScript i jego pakiet SDK w wersji 8. Interfejsy API biblioteki są w znacznym stopniu w inny sposób. Zalecamy korzystanie z biblioteki testowej v9, która jest prostsza w obsłudze wymaga mniej konfiguracji, aby można było łączyć się z emulatorami, i bezpiecznie uniknąć przypadkowego wykorzystanie zasobów produkcyjnych. Aby zapewnić zgodność wsteczną, wprowadzamy dostępna biblioteka do testowania wersji 8.

Interakcja z emulatorem za pomocą modułu @firebase/rules-unit-testing który działa lokalnie. Jeśli wystąpi przekroczenie limitu czasu oczekiwania lub ECONNREFUSED błąd, sprawdź jeszcze raz że emulator działa.

Zdecydowanie zalecamy korzystanie z najnowszej wersji środowiska Node.js, co pozwoli Ci korzystać z Zapis async/await. Prawie wszystkie zachowania, które warto przetestować obejmuje funkcje asynchroniczne, a moduł testowania jest przeznaczony do działania Kod oparty na obietnicy.

Biblioteka testowania jednostkowego w wersji 9 zawsze wie o emulatorach i nigdy zasobów produkcyjnych.

Bibliotekę zaimportujesz za pomocą modułowych instrukcji importowania w wersji 9. Przykład:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment
} from "@firebase/rules-unit-testing"

// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.

Po zaimportowaniu testy jednostkowe obejmują:

  • Tworzenie i konfigurowanie obiektu RulesTestEnvironment z wywołaniem initializeTestEnvironment
  • Konfigurowanie danych testowych bez uruchamiania reguł, korzystając z wygody która pozwala tymczasowo je ominąć, RulesTestEnvironment.withSecurityRulesDisabled
  • Konfigurowanie pakietu testowego i punktów zaczepienia przed i po każdym teście z wywołaniami wyczyść dane testowe i środowisko, takie jak RulesTestEnvironment.cleanup() lub RulesTestEnvironment.clearFirestore().
  • Wdrażanie przypadków testowych, które naśladują stany uwierzytelniania za pomocą RulesTestEnvironment.authenticatedContext i RulesTestEnvironment.unauthenticatedContext

Typowe metody i funkcje użytkowe

Zobacz też metody testowe związane z emulatorami w pakiecie SDK w wersji 9.

initializeTestEnvironment() => RulesTestEnvironment

Ta funkcja inicjuje środowisko testowe do testowania jednostkowego reguł. Zadzwoń dla konfiguracji testu. Aby się udało, emulatory muszą być w domu.

Funkcja akceptuje opcjonalny obiekt definiujący TestEnvironmentConfig, który może składać się z identyfikatora projektu i ustawień konfiguracji emulatora.

let testEnv = await initializeTestEnvironment({
  projectId: "demo-project-1234",
  firestore: {
    rules: fs.readFileSync("firestore.rules", "utf8"),
  },
});

RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext

Ta metoda tworzy RulesTestContext, który działa jak uwierzytelniony Uwierzytelnianie użytkownika. Żądania utworzone przy użyciu zwróconego kontekstu będą miały model Dołączono token uwierzytelniania. Opcjonalnie prześlij obiekt definiujący deklaracje niestandardowe lub zastąpienia dla ładunków tokenów uwierzytelniania.

Użyj zwróconego obiektu kontekstu testowego w testach, aby uzyskać dostęp do dowolnego emulatora skonfigurowanych instancji, w tym tych ze skonfigurowanych przy użyciu initializeTestEnvironment.

// Assuming a Firestore app and the Firestore emulator for this example
import { setDoc } from "firebase/firestore";

const alice = testEnv.authenticatedContext("alice", { … });
// Use the Firestore instance associated with this context
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

Ta metoda tworzy obiekt RulesTestContext, który działa jak klient, który jest Użytkownik nie zalogował się przez Uwierzytelnianie. Żądania utworzone za pomocą zwróconego kontekstu nie będą tokeny uwierzytelniania Firebase.

Użyj zwróconego obiektu kontekstu testowego w testach, aby uzyskać dostęp do dowolnego emulatora skonfigurowanych instancji, w tym tych ze skonfigurowanych przy użyciu initializeTestEnvironment.

// Assuming a Cloud Storage app and the Storage emulator for this example
import { getStorage, ref, deleteObject } from "firebase/storage";

const alice = testEnv.unauthenticatedContext();

// Use the Cloud Storage instance associated with this context
const desertRef = ref(alice.storage(), 'images/desert.jpg');
await assertSucceeds(deleteObject(desertRef));

RulesTestEnvironment.withSecurityRulesDisabled()

Uruchom funkcję konfiguracji testowej z kontekstem, który działa tak, jakby reguły zabezpieczeń wyłączono.

Ta metoda korzysta z funkcji wywołania zwrotnego, która wykorzystuje funkcję omijania reguł zabezpieczeń i zwraca obietnicę. Kontekst zostanie zniszczony, gdy obietnica podejmie decyzję lub ją odrzuci.

RulesTestEnvironment.cleanup()

Ta metoda niszczy wszystkie RulesTestContexts utworzone w środowisku testowym i czyści bazowe zasoby, pozostawiając czyste wyjście.

Ta metoda nie zmienia w żaden sposób stanu emulatorów. Resetowanie danych między kolejnymi testami należy użyć metody jasnej danych specyficznej dla emulatora aplikacji.

assertSucceeds(pr: Promise<any>)) => Promise<any>

To jest funkcja narzędziowa przypadku testowego.

Funkcja potwierdza, że podana usługa Promise opakowuje operację emulatora zostanie rozwiązany bez naruszeń reguł zabezpieczeń.

await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

assertFails(pr: Promise<any>)) => Promise<any>

To jest funkcja narzędziowa przypadku testowego.

Funkcja potwierdza, że podana usługa Promise opakowuje operację emulatora zostanie odrzucona z powodu naruszenia reguł zabezpieczeń.

await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });

Metody specyficzne dla emulatora

Zapoznaj się też z typowymi metodami testowania i funkcjami narzędziowymi w pakiecie SDK w wersji 9.

RulesTestEnvironment.clearFirestore() => Promise<void>

Ta metoda usuwa w bazie danych Firestore dane, które należą do Uprawnienia projectId zostały skonfigurowane dla emulatora Firestore.

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

Ta metoda pobiera instancję Firestore na potrzeby tego kontekstu testowego. Zwrócone wartości Instancji pakietu SDK Firebase JS Client SDK można używać z interfejsami API pakietu SDK klienta (modułowa wersja 9) lub zgodnego z wersją 9).

Wizualizacja ocen reguł

Emulator Cloud Firestore umożliwia wizualizację żądań klientów w interfejsu użytkownika Pakietu emulatorów, w tym śledzenia oceny dla reguł zabezpieczeń Firebase.

Otwórz Firestore > Prośby, aby wyświetlić szczegółową ocenę. dla każdego żądania.

Monitor żądań emulatora Firestore pokazujący oceny reguł zabezpieczeń

Generowanie raportów z testów

Po przeprowadzeniu zestawu testów możesz uzyskać dostęp do testów raporty o zasięgu, które pokazują, jak została oceniona każda z Twoich reguł zabezpieczeń.

Aby uzyskać te raporty, wyślij w emulatorze zapytanie do ujawnionego punktu końcowego, podczas gdy jego uruchomienie. W przypadku wersji przeznaczonej do wyświetlania w przeglądarce użyj tego adresu URL:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html

Reguły są dzielone na wyrażenia i podwyrażenia, najechanie kursorem myszy, aby uzyskać więcej informacji, w tym liczbę ocen i wartości . W przypadku nieprzetworzonej wersji JSON tych danych dołącz ten adres URL w zapytaniu:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage

Różnice między emulatorem a produkcją

  1. Nie musisz bezpośrednio tworzyć projektu Cloud Firestore. Emulator automatycznie tworzy każdą instancję, do której uzyskano dostęp.
  2. Emulator Cloud Firestore nie działa z zwykłym przepływem uwierzytelniania Firebase. W pakiecie SDK Firebase Test SDK udostępniliśmy metodę initializeTestApp() w parametrze Biblioteka rules-unit-testing, która zajmuje pole auth. Utworzono nick Firebase używając tej metody, będzie działać tak, jakby została pomyślnie uwierzytelniona jako bez względu na nazwę podmiotu. Jeśli przekażesz zasadę null, będzie ona działać jako nieuwierzytelniony użytkownik (na przykład reguły auth != null zakończą się niepowodzeniem).

Rozwiązywanie znanych problemów

Podczas używania emulatora Cloud Firestore możesz napotkać te znane: problemów. Aby rozwiązać problem z nieprawidłowym zachowaniem, postępuj zgodnie z poniższymi wskazówkami z całego świata. Te notatki są tworzone podczas testowania jednostkowego reguł zabezpieczeń ale ogólne podejścia mają zastosowanie do każdego pakietu SDK Firebase.

Działanie testu jest niespójne

Jeśli testy są czasami zaliczone i kończą się niepowodzeniem, nawet jeśli nie wprowadzasz żadnych zmian samodzielnie testujących, warto sprawdzić, czy mają prawidłową sekwencję. Większość interakcji z emulatorem jest asynchroniczna, więc sprawdź dokładnie, czy wszystkie dla kodu asynchronicznego należy zastosować odpowiednią sekwencję. Sekwencjonowanie możesz poprawić, wykonując jedną z tych czynności: łańcuch obietnic lub swobodne korzystanie z notacji await.

W szczególności sprawdź te operacje asynchroniczne:

  • Ustawianie reguł zabezpieczeń, na przykład initializeTestEnvironment.
  • Odczyt i zapis danych, np. db.collection("users").doc("alice").get().
  • Potwierdzenia działań, w tym assertSucceeds i assertFails.

Testy zaliczają się tylko przy pierwszym wczytaniu emulatora

Emulator jest stanowy. Przechowuje wszystkie zapisane w niej dane w pamięci, wyłączenie emulatora spowoduje utratę danych. Jeśli masz wiele reklam testów z tym samym identyfikatorem projektu, każdy test może dostarczyć dane, które mogą wpłynąć na kolejne testy. Możesz użyć dowolnej z tych metod, aby: omiń to zachowanie:

  • W każdym teście używaj unikalnych identyfikatorów projektów. Pamiętaj, że jeśli to zrobisz, musi wywołać funkcję initializeTestEnvironment w ramach każdego testu; reguły są ładowane automatycznie tylko dla domyślnego identyfikatora projektu.
  • Przeorganizuj testy tak, aby nie wchodziły w interakcje z wcześniej zapisanymi danymi (np. dla każdego testu użyj innej kolekcji).
  • Usuń wszystkie dane zapisane podczas testu.

Konfiguracja testu jest bardzo skomplikowana

Podczas konfigurowania testu warto zmodyfikować dane w taki sposób, aby Reguły zabezpieczeń Cloud Firestore w rzeczywistości nie zezwalają na korzystanie z tej funkcji. Jeśli reguły powodują konfigurację testu złożone, spróbuj użyć w konfiguracji usługi RulesTestEnvironment.withSecurityRulesDisabled kroków, więc odczyty i zapisy nie będą wywoływać błędów PERMISSION_DENIED.

Po tym czasie test może wykonywać operacje jako uwierzytelniony lub nieuwierzytelniony użytkownik korzystający z funkcji RulesTestEnvironment.authenticatedContext i unauthenticatedContext . Pozwoli Ci to sprawdzić, czy reguły zabezpieczeń Cloud Firestore zezwalają na korzystanie z usługi lub jej nie zezwalają poszczególne przypadki.