Przetestuj swoje reguły bezpieczeństwa Cloud Firestore

Podczas tworzenia aplikacji możesz zablokować dostęp do bazy danych Cloud Firestore. Jednak przed uruchomieniem będziesz potrzebować bardziej zniuansowanych reguł bezpieczeństwa Cloud Firestore. Za pomocą emulatora Cloud Firestore możesz pisać testy jednostkowe, które sprawdzają zachowanie reguł zabezpieczeń Cloud Firestore.

Szybki start

Przez kilka podstawowych testów o prostych zasadach, wypróbować próbkę quickstart .

Zrozumienie reguł bezpieczeństwa Cloud Firestore

Wdrożenia uwierzytelniania Firebase i Chmura FireStore Reguły zabezpieczeń dla Serverless uwierzytelniania, autoryzacji i walidacji danych podczas korzystania z telefonów i sieci bibliotek klienta.

Zasady bezpieczeństwa Cloud Firestore obejmują dwie części:

  1. match rachunku, który identyfikuje dokumenty w bazie danych.
  2. allow wyrażenie, które kontroluje dostęp do tych dokumentów.

Uwierzytelnianie Firebase weryfikuje poświadczenia 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 reguł bezpieczeństwa przed odczytaniem lub zapisaniem jakichkolwiek danych. Jeśli reguły odmawiają dostępu do dowolnej z określonych ścieżek dokumentów, całe żądanie kończy się niepowodzeniem.

Dowiedz się więcej o cloud regulaminu Firestore Bezpieczeństwem w Zacząć z chmurą FireStore zasad bezpieczeństwa .

Zainstaluj emulator

Aby zainstalować emulator Chmura FireStore użyj Firebase CLI i uruchom polecenie poniżej:

firebase setup:emulators:firestore

Uruchom emulator

Zacznij od zainicjowania projektu Firebase w katalogu roboczym. Jest to wspólny Pierwszym krokiem przy użyciu Firebase CLI .

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żna to zrobić łatwo za pomocą emulators:exec polecenie:

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

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

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

Zanim uruchomisz emulator

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

  • Emulator będzie początkowo załadować zasady określone w firestore.rules zakresie swojej firebase.json pliku. Oczekuje nazwy pliku lokalnego zawierającego reguły bezpieczeństwa Cloud Firestore i stosuje te reguły do ​​wszystkich projektów. Jeśli nie zapewniają lokalną ścieżkę do pliku lub użyć loadFirestoreRules sposób jak opisano poniżej, traktuje emulatora wszystkich projektów, jak mając otwarte zasad.
  • Podczas gdy większość Firebase SDK praca z emulatorów bezpośrednio, tylko @firebase/rules-unit-testing obsługuje biblioteki szyderczy auth w przepisach bezpieczeństwa, dzięki czemu testy jednostkowe znacznie łatwiejsze. Ponadto biblioteka obsługuje kilka funkcji specyficznych dla emulatora, takich jak czyszczenie wszystkich danych, które wymieniono poniżej.
  • Emulatory będą również akceptować produkcyjne tokeny uwierzytelniania Firebase dostarczane za pośrednictwem pakietów Client SDK i odpowiednio oceniać reguły, co pozwala na połączenie aplikacji bezpośrednio z emulatorami w ramach testów integracyjnych i ręcznych.

Uruchom lokalne testy

initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp

Ta metoda zwraca zainicjowaną aplikację Firebase odpowiadającą identyfikatorowi projektu i zmiennej uwierzytelniania określonej w opcjach. Użyj tego, aby utworzyć aplikację uwierzytelnioną jako określony użytkownik do użycia w testach.

firebase.initializeTestApp({
  projectId: "my-test-project",
  auth: { uid: "alice", email: "alice@example.com" }
});

initializeAdminApp({ projectId: string }) => FirebaseApp

Ta metoda zwraca zainicjowaną administracyjną aplikację Firebase. Ta aplikacja omija reguły bezpieczeństwa podczas wykonywania odczytów i zapisów. Użyj tego, aby utworzyć aplikację uwierzytelnioną jako administrator, aby ustawić stan dla testów.

firebase.initializeAdminApp({ projectId: "my-test-project" });
    

apps() => [FirebaseApp] Metoda ta zwraca wszystkie aktualnie inicjowane testowe i administracja aplikacji. Użyj tego, aby wyczyścić aplikacje między testami lub po nich.

Promise.all(firebase.apps().map(app => app.delete()))

loadFirestoreRules({ projectId: string, rules: Object }) => Promise

Ta metoda wysyła reguły do ​​lokalnie działającej bazy danych. Pobiera obiekt, który określa reguły jako ciąg. Użyj tej metody, aby ustawić reguły bazy danych.

firebase.loadFirestoreRules({
  projectId: "my-test-project",
  rules: fs.readFileSync("/path/to/firestore.rules", "utf8")
});
    

assertFails(pr: Promise) => Promise

Ta metoda zwraca obietnicę, która jest odrzucana, jeśli dane wejściowe się powiedzie lub które powiedzie się, jeśli dane wejściowe zostaną odrzucone. Użyj tego, aby potwierdzić, jeśli odczyt lub zapis bazy danych nie powiedzie się.

firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
    

assertSucceeds(pr: Promise) => Promise

Ta metoda zwraca obietnicę, która się powiedzie, jeśli dane wejściowe się powiedzie i zostaną odrzucone, jeśli dane wejściowe zostaną odrzucone. Użyj tego, aby potwierdzić, czy odczyt lub zapis bazy danych powiedzie się.

firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
    

clearFirestoreData({ projectId: string }) => Promise

Ta metoda usuwa wszystkie dane powiązane z konkretnym projektem w lokalnie działającej instancji Firestore. Użyj tej metody do czyszczenia po testach.

firebase.clearFirestoreData({
  projectId: "my-test-project"
});
   

Generuj raporty z testów

Po uruchomieniu zestawu testów możesz uzyskać dostęp do raportów dotyczących pokrycia testami, które pokazują, w jaki sposób oceniono każdą z Twoich reguł bezpieczeństwa.

Aby uzyskać raporty, wykonaj zapytanie do odsłoniętego punktu końcowego w emulatorze podczas jego działania. 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 podwyrażenia, na które można najechać kursorem myszy, aby uzyskać więcej informacji, w tym liczbę zwróconych ocen i wartości. W przypadku nieprzetworzonej wersji JSON tych danych 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żde wystąpienie, do którego uzyskuje się dostęp.
  2. Emulator Cloud Firestore nie działa z normalnym przepływem Uwierzytelniania Firebase. Zamiast tego, w Firebase testowym SDK, my dostarczyły initializeTestApp() metoda w rules-unit-testing biblioteki, która zajmuje auth pole. Dojście Firebase utworzone przy użyciu tej metody będzie zachowywać się tak, jakby zostało pomyślnie uwierzytelnione jako dowolna podana przez Ciebie jednostka. Jeśli przechodzą w null , będzie zachowywać się jak niezidentyfikowany użytkownik ( auth != null reguły nie powiedzie się, na przykład).

Rozwiązywanie znanych problemów

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 pakiecie Firebase Test SDK, ale ogólne podejście można zastosować do każdego pakietu Firebase SDK.

Zachowanie testowe jest niespójne

Jeśli twoje testy od czasu do czasu przechodzą i kończą się niepowodzeniem, nawet bez żadnych zmian w samych testach, może być konieczne sprawdzenie, czy są one prawidłowo zsekwencjonowane. Większość interakcji z emulatorem jest asynchroniczna, dlatego należy dokładnie sprawdzić, czy cały kod asynchroniczny jest prawidłowo zsekwencjonowany. Można naprawić albo przez sekwencjonowanie łańcuchowym obietnic, lub za pomocą await notacji liberalnie.

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

  • Ustawianie zasad bezpieczeństwa, z, na przykład, firebase.loadFirestoreRules .
  • Odczyt i zapis danych, z, na przykład, db.collection("users").doc("alice").get() .
  • Twierdzenia operacyjne, w tym firebase.assertSucceeds i firebase.assertFails .

Testy przechodzą tylko przy pierwszym załadowaniu emulatora

Emulator jest stanowy. Przechowuje wszystkie zapisane w nim dane w pamięci, więc wszelkie dane są tracone po każdym wyłączeniu emulatora. Jeśli uruchamiasz wiele testów z tym samym identyfikatorem 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 projektu dla każdego testu. Należy pamiętać, że jeśli zdecydujesz się to zrobić, trzeba będzie zadzwonić loadFirestoreRules w ramach każdego badania; reguły są automatycznie ładowane tylko dla domyślnego identyfikatora projektu.
  • Zmień strukturę testów, aby nie wchodziły w interakcje z wcześniej pisanymi danymi (na przykład użyj innej kolekcji dla każdego testu).
  • Usuń wszystkie dane zapisane podczas testu.

Konfiguracja testu jest bardzo skomplikowana

Warto przetestować scenariusze, na które nie zezwalają reguły zabezpieczeń Cloud Firestore. Na przykład testowanie, czy nieuwierzytelnieni użytkownicy mogą edytować dane, jest trudne do przetestowania, ponieważ nie możesz edytować danych jako użytkownik nieuwierzytelniony.

Jeśli Twoje reguły utrudniają konfigurację testu, spróbuj użyć klienta autoryzowanego przez administratora, aby ominąć reguły. Można to zrobić z firebase.initializeAdminApp . Czyta i pisze z klientami administratora autoryzowany bypassu przepisami i nie wywołać PERMISSION_DENIED błędów.