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 Cloud Firestore Security Rules Oprócz tworzenia prototypów za pomocą emulatora Cloud Firestore oraz testowanie ogólnych funkcji i działania aplikacji, można pisać testy jednostkowe, które sprawdzają działanie Cloud Firestore Security Rules.

Krótkie wprowadzenie

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

Poznaj Cloud Firestore Security Rules

Wdróż Firebase Authentication oraz Cloud Firestore Security Rules dla usług bezserwerowych uwierzytelniania, autoryzacji i weryfikacji danych podczas korzystania bibliotek klienta internetowego.

Cloud Firestore Security Rules obejmuje 2 elementy:

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

Firebase Authentication weryfikuje dane logowania użytkowników 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 usłudze Cloud Firestore Security Rules znajdziesz w artykule Pierwsze kroki z Cloud Firestore Security Rules.

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 należy uruchomić emulator, uruchomić zestaw testów, a potem go zamknąć. 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:

  • Na początku emulator wczyta reguły określone w polu firestore.rulespliku firebase.json. Oczekuje ona nazwy lokalnego pliku, który zawiera Cloud Firestore Security Rules, 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. Dodatkowo biblioteka obsługuje kilka funkcji związanych z konkretnym emulatorem, takich jak czyszczenie wszystkich danych, które wymieniono 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.

Do interakcji z lokalnie uruchomionym emulatorem służy moduł @firebase/rules-unit-testing. 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ę importujesz za pomocą instrukcji importu modułowego v9. 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 testów jednostkowych ich implementacja obejmuje:

  • Tworzenie i konfigurowanie obiektu RulesTestEnvironment z wywołaniem initializeTestEnvironment
  • Konfigurowanie danych testowych bez uruchamiania reguł za pomocą wygodnej metody, która pozwala na ich tymczasowe pominięcie:RulesTestEnvironment.withSecurityRulesDisabled.
  • Konfigurowanie zestawu testów i funkcji przed testem lub po nim z wywołaniem do funkcji czyszczących dane testowe i środowisko, np. 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 roszczenia niestandardowe lub zastąpienia dla danych tokena uwierzytelniania.

Używaj zwracanego obiektu test context w testach, aby uzyskać dostęp do skonfigurowanych instancji emulatora, w tym do tych 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 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 pomocnicza testowego przypadku użycia.

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

Zobacz też popularne metody testowania i funkcje pomocnicze 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 uruchomieniu zestawu testów możesz uzyskać dostęp do raportów o zakresie testów, które pokazują, jak oceniono każdą z reguł bezpieczeństwa.

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 wersją produkcyjną

  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 w zwykłym procesie Firebase Authentication. Zamiast tego w pakiecie Firebase Test SDK udostępniliśmy w bibliotece rules-unit-testing metodę initializeTestApp(), która przyjmuje 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ć problemy z nieprawidłowym działaniem, postępuj zgodnie z instrukcjami poniżej. 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.
  • odczytywanie i zapisywanie 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:

  • Używaj unikalnych identyfikatorów projektów w przypadku każdego testu. 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 Cloud Firestore Security Rules nie zezwalają na dostęp. 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 Cloud Firestore Security Rules zezwala / nie zezwala na dostęp poszczególne przypadki.