Catch up on highlights from Firebase at Google I/O 2023. Learn more

Przetestuj swoje reguły bezpieczeństwa Cloud Firestore

Podczas tworzenia aplikacji możesz chcieć zablokować dostęp do bazy danych Cloud Firestore. Jednak przed uruchomieniem będziesz potrzebować bardziej szczegółowych reguł bezpieczeństwa Cloud Firestore. Dzięki emulatorowi Cloud Firestore, oprócz prototypowania i testowania ogólnych funkcji i zachowania aplikacji, możesz pisać testy jednostkowe, które sprawdzają zachowanie reguł bezpieczeństwa Cloud Firestore.

Szybki start

Aby zapoznać się z kilkoma podstawowymi przypadkami testowymi z prostymi regułami, wypróbuj próbkę szybkiego startu .

Zapoznaj się z zasadami bezpieczeństwa Cloud Firestore

Zaimplementuj reguły bezpieczeństwa Firebase Authentication i Cloud Firestore do uwierzytelniania bezserwerowego, autoryzacji i sprawdzania poprawności danych podczas korzystania z bibliotek klienta mobilnego i internetowego.

Reguły bezpieczeństwa Cloud Firestore obejmują dwie części:

  1. Instrukcja match , która identyfikuje dokumenty w bazie danych.
  2. allow zezwalające kontrolujące dostęp do tych dokumentów.

Uwierzytelnianie Firebase weryfikuje poświadczenia użytkowników i zapewnia podstawę dla 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 reguł bezpieczeństwa przed odczytaniem lub zapisaniem jakichkolwiek danych. Jeśli reguły odmówią dostępu do którejkolwiek z określonych ścieżek dokumentów, całe żądanie zakończy się niepowodzeniem.

Dowiedz się więcej o regułach bezpieczeństwa Cloud Firestore w artykule Pierwsze kroki z regułami bezpieczeństwa Cloud Firestore .

Zainstaluj emulator

Aby zainstalować emulator Cloud Firestore, użyj Firebase CLI i uruchom poniższe polecenie:

firebase setup:emulators:firestore

Uruchom emulator

Rozpocznij od zainicjowania projektu Firebase w swoim katalogu roboczym. Jest to częsty pierwszy krok podczas korzystania z interfejsu wiersza polecenia Firebase .

firebase init

Uruchom emulator za pomocą następującego polecenia. Emulator będzie działał, dopóki nie zabijesz procesu:

firebase emulators:start --only firestore

W wielu przypadkach chcesz uruchomić emulator, uruchomić zestaw testów, a następnie zamknąć emulator po uruchomieniu testów. Możesz to łatwo zrobić za pomocą polecenia emulators:exec :

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

Po uruchomieniu emulator spróbuje uruchomić się na domyślnym porcie (8080). Możesz zmienić port emulatora, modyfikując sekcję "emulators" w pliku firebase.json :

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

Przed uruchomieniem emulatora

Zanim zaczniesz korzystać z emulatora, pamiętaj o następujących kwestiach:

  • Emulator początkowo załaduje reguły określone w polu firestore.rules pliku firebase.json . Oczekuje nazwy lokalnego pliku zawierającego reguły bezpieczeństwa Cloud Firestore i stosuje te reguły do ​​wszystkich projektów. Jeśli nie podasz lokalnej ścieżki do pliku lub nie użyjesz metody loadFirestoreRules zgodnie z poniższym opisem, emulator traktuje wszystkie projekty jako mające otwarte reguły.
  • Podczas gdy większość zestawów SDK Firebase współpracuje bezpośrednio z emulatorami, tylko biblioteka @firebase/rules-unit-testing obsługuje fałszywe auth w regułach bezpieczeństwa, co znacznie ułatwia testy jednostkowe. Ponadto biblioteka obsługuje kilka funkcji specyficznych dla emulatora, takich jak czyszczenie wszystkich danych, jak wymieniono poniżej.
  • Emulatory akceptują również produkcyjne tokeny Firebase Auth dostarczane za pośrednictwem SDK klienta i odpowiednio oceniają reguły, co umożliwia bezpośrednie połączenie aplikacji z emulatorami w testach integracyjnych i ręcznych.

Uruchom lokalne testy jednostkowe

Przeprowadzaj lokalne testy jednostkowe za pomocą zestawu SDK języka JavaScript w wersji 9

Firebase dystrybuuje bibliotekę testów jednostkowych reguł bezpieczeństwa wraz z pakietem SDK JavaScript w wersji 9 i pakietem SDK w wersji 8. Interfejsy API bibliotek znacznie się różnią. Zalecamy bibliotekę testową v9, która jest bardziej usprawniona i wymaga mniej konfiguracji w celu połączenia z emulatorami, a tym samym bezpiecznie unika przypadkowego użycia zasobów produkcyjnych. Aby zapewnić kompatybilność wsteczną, nadal udostępniamy bibliotekę testową w wersji 8 .

Użyj modułu @firebase/rules-unit-testing do interakcji z emulatorem działającym lokalnie. Jeśli wystąpią przekroczenia limitu czasu lub błędy ECONNREFUSED , dokładnie sprawdź, czy emulator faktycznie działa.

Zdecydowanie zalecamy korzystanie z najnowszej wersji Node.js, aby można było używać notacji async/await . Niemal wszystkie zachowania, które możesz chcieć przetestować, obejmują funkcje asynchroniczne, a moduł testowania został zaprojektowany do pracy z kodem opartym na obietnicach.

Biblioteka v9 Rules Unit Testing jest zawsze świadoma istnienia emulatorów i nigdy nie dotyka Twoich zasobów produkcyjnych.

Importujesz bibliotekę za pomocą modułowych instrukcji importu v9. Na przykład:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment,
  RulesTestEnvironment,
} 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 wdrożenie testów jednostkowych obejmuje:

  • Tworzenie i konfigurowanie RulesTestEnvironment z wywołaniem metody initializeTestEnvironment .
  • Konfigurowanie danych testowych bez wyzwalania reguł przy użyciu wygodnej metody umożliwiającej tymczasowe ich pominięcie — RulesTestEnvironment.withSecurityRulesDisabled .
  • Konfigurowanie zestawu testów i poszczególnych testów przed/po wiąże się z wywołaniami do czyszczenia danych testowych i środowiska, takimi jak RulesTestEnvironment.cleanup() lub RulesTestEnvironment.clearFirestore() .
  • Implementacja przypadków testowych, które naśladują stany uwierzytelniania przy użyciu RulesTestEnvironment.authenticatedContext i RulesTestEnvironment.unauthenticatedContext .

Typowe metody i funkcje użytkowe

Zobacz także metody testowania specyficzne dla emulatora w pakiecie SDK v9 .

initializeTestEnvironment() => RulesTestEnvironment

Ta funkcja inicjuje środowisko testowe dla testów jednostkowych reguł. Wywołaj tę funkcję najpierw w celu konfiguracji testu. Pomyślne wykonanie wymaga uruchomienia emulatorów.

Funkcja akceptuje opcjonalny obiekt definiujący TestEnvironmentConfig , który może składać się z identyfikatora projektu i ustawień konfiguracyjnych 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óra zachowuje się jak uwierzytelniony użytkownik uwierzytelniania. Żądania utworzone za pośrednictwem zwróconego kontekstu będą miały dołączony fałszywy token uwierzytelniania. Opcjonalnie Przekaż obiekt definiujący niestandardowe oświadczenia lub przesłonięcia dla ładunków tokenu uwierzytelniania.

Użyj zwróconego obiektu kontekstu testowego w swoich testach, aby uzyskać dostęp do wszystkich skonfigurowanych wystąpień emulatora, w tym skonfigurowanych za pomocą 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 RulesTestContext , która zachowuje się jak klient, który nie jest zalogowany za pośrednictwem uwierzytelniania. Żądania utworzone za pośrednictwem zwróconego kontekstu nie będą miały dołączonych tokenów Firebase Auth.

Użyj zwróconego obiektu kontekstu testowego w swoich testach, aby uzyskać dostęp do wszystkich skonfigurowanych wystąpień emulatora, w tym skonfigurowanych za pomocą 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 testu z kontekstem, który zachowuje się tak, jakby reguły bezpieczeństwa były wyłączone.

Ta metoda przyjmuje funkcję wywołania zwrotnego, która przyjmuje kontekst omijania zasad zabezpieczeń i zwraca obietnicę. Kontekst zostanie zniszczony, gdy obietnica zostanie rozwiązana / odrzucona.

RulesTestEnvironment.cleanup()

Ta metoda niszczy wszystkie RulesTestContexts utworzone w środowisku testowym i czyści podstawowe zasoby, umożliwiając czyste wyjście.

Ta metoda w żaden sposób nie zmienia stanu emulatorów. Aby zresetować dane między testami, użyj metody czyszczenia danych specyficznej dla emulatora aplikacji.

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

Jest to funkcja użyteczności przypadków testowych.

Funkcja zapewnia, że ​​dostarczona obietnica zawijająca operację emulatora zostanie rozwiązana bez naruszenia zasad bezpieczeństwa.

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

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

Jest to funkcja użyteczności przypadków testowych.

Funkcja zapewnia, że ​​dostarczona obietnica zawijająca operację emulatora zostanie odrzucona z naruszeniem zasad bezpieczeństwa.

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

Metody specyficzne dla emulatora

Zapoznaj się również z typowymi metodami testowania i funkcjami narzędzi w pakiecie SDK v9 .

RulesTestEnvironment.clearFirestore() => Promise<void>

Ta metoda czyści dane w bazie danych Firestore, które należą do projectId skonfigurowanego dla emulatora Firestore.

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

Ta metoda pobiera instancję Firestore dla tego kontekstu testowego. Zwrócona instancja Firebase JS Client SDK może być używana z interfejsami API klienta SDK (v9 modular lub v9 Compat).

Wizualizuj oceny reguł

Emulator Cloud Firestore umożliwia wizualizację żądań klientów w interfejsie Emulator Suite, w tym śledzenie oceny reguł bezpieczeństwa Firebase.

Otwórz kartę Firestore > Żądania , aby wyświetlić szczegółową sekwencję oceny dla każdego żądania.

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

Generuj raporty z testów

Po przeprowadzeniu zestawu testów możesz uzyskać dostęp do raportów pokrycia testów, które pokazują, jak oceniono każdą z reguł bezpieczeństwa.

Aby uzyskać raporty, wyślij zapytanie do uwidocznionego punktu końcowego w emulatorze, gdy jest on uruchomiony. Aby uzyskać wersję przyjazną dla przeglądarki, użyj następującego adresu URL:

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

Spowoduje to rozbicie reguł na wyrażenia i wyrażenia podrzędne, na które można najechać kursorem myszy, aby uzyskać więcej informacji, w tym liczbę ocen i zwróconych wartości. Aby uzyskać nieprzetworzoną wersję tych danych w formacie JSON, w zapytaniu uwzględnij następujący adres URL:

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

Różnice między emulatorem a produkcją

  1. Nie musisz jawnie tworzyć projektu Cloud Firestore. Emulator automatycznie tworzy każdą dostępną instancję.
  2. Emulator Cloud Firestore nie działa z normalnym przepływem uwierzytelniania Firebase. Zamiast tego w Firebase Test SDK udostępniliśmy metodę initializeTestApp() w bibliotece rules-unit-testing , która pobiera pole auth . Uchwyt Firebase utworzony przy użyciu tej metody będzie zachowywał się tak, jakby został pomyślnie uwierzytelniony jako dowolna podana jednostka. Jeśli przekażesz null , będzie się zachowywał jak nieuwierzytelniony użytkownik (na przykład reguły auth != null zawiodą).

Rozwiąż znane problemy

Podczas korzystania z emulatora Cloud Firestore możesz napotkać następujące znane problemy. Postępuj zgodnie z poniższymi wskazówkami, aby rozwiązać problemy z nieprawidłowym zachowaniem. Te uwagi zostały napisane z myślą o bibliotece testów jednostkowych Reguł bezpieczeństwa, ale ogólne podejście ma zastosowanie do każdego pakietu SDK Firebase.

Zachowanie testowe jest niespójne

Jeśli Twoje testy okazjonalnie przechodzą i kończą się niepowodzeniem, nawet bez żadnych zmian w samych testach, może być konieczne sprawdzenie, czy są one prawidłowo uporządkowane. Większość interakcji z emulatorem ma charakter asynchroniczny, więc dokładnie sprawdź, czy cały kod asynchroniczny jest odpowiednio ułożony. Możesz naprawić sekwencjonowanie, łącząc obietnice lub swobodnie używając notacji await .

W szczególności przejrzyj następujące operacje asynchroniczne:

  • Ustawianie reguł bezpieczeństwa, na przykład initializeTestEnvironment .
  • Odczytywanie i zapisywanie danych, na przykład db.collection("users").doc("alice").get() .
  • Asercje operacyjne, w tym assertSucceeds i assertFails .

Testy przechodzą tylko przy pierwszym załadowaniu emulatora

Emulator jest stanowy. Przechowuje wszystkie dane zapisane w pamięci, więc wszelkie dane są tracone po wyłączeniu emulatora. Jeśli przeprowadzasz wiele testów dla tego samego identyfikatora projektu, każdy test może generować dane, które mogą mieć wpływ na kolejne testy. Możesz użyć dowolnej z następujących metod, aby ominąć to zachowanie:

  • Używaj unikalnych identyfikatorów projektów dla każdego testu. Zauważ, że jeśli zdecydujesz się to zrobić, będziesz musiał wywołać initializeTestEnvironment jako część każdego testu; reguły są ładowane automatycznie tylko dla domyślnego identyfikatora projektu.
  • Zrestrukturyzuj swoje testy, aby nie wchodziły w interakcje z wcześniej zapisanymi danymi (na przykład użyj innej kolekcji dla każdego testu).
  • Usuń wszystkie dane zapisane podczas testu.

Konfiguracja testu jest bardzo skomplikowana

Podczas konfigurowania testu możesz chcieć zmodyfikować dane w sposób, na który reguły bezpieczeństwa Cloud Firestore w rzeczywistości nie pozwalają. Jeśli Twoje reguły sprawiają, że konfiguracja testów jest złożona, spróbuj użyć RulesTestEnvironment.withSecurityRulesDisabled w krokach konfiguracji, aby odczyty i zapisy nie powodowały błędów PERMISSION_DENIED .

Następnie Twój test może wykonywać operacje jako uwierzytelniony lub nieuwierzytelniony użytkownik, używając odpowiednio RulesTestEnvironment.authenticatedContext i unauthenticatedContext . Dzięki temu możesz zweryfikować, czy reguły bezpieczeństwa Cloud Firestore prawidłowo zezwalają na różne przypadki lub je odrzucają.