Testare le regole di sicurezza

Durante la creazione dell'app, ti consigliamo di bloccare l'accesso al database Firestore. Tuttavia, prima del lancio, avrai bisogno di regole di sicurezza di Firestore più dettagliate. Con l'emulatore Firestore, oltre a creare un prototipo e a testare le funzionalità e il comportamento generali della tua app, puoi scrivere test di unità che controllano il comportamento delle regole di sicurezza di Firestore.

Guida rapida

Per alcuni casi di test di base con regole semplici, prova l'esempio di avvio rapido.

Comprendi le regole di sicurezza di Firestore

Implementa Firebase Authentication e Regole di sicurezza di Firestore per l'autenticazione, l'autorizzazione e la convalida dei dati serverless quando utilizzi le librerie client per applicazioni web o per dispositivi mobili.

Le Regole di sicurezza di Firestore includono due elementi:

  1. Un'istruzione match che identifica i documenti nel database.
  2. Un'espressione allow che controlla l'accesso a questi documenti.

Firebase Authentication verifica gli account utente credenziali e fornisce le basi sistemi di accesso basati su utenti e ruoli.

Ogni richiesta al database da una libreria client mobile/web Firestore viene valutata in base alle tue regole di sicurezza prima di leggere o scrivere dati. Se le regole negano l'accesso a uno qualsiasi dei percorsi dei documenti specificati, l'intera non va a buon fine.

Scopri di più sulle regole di sicurezza di Firestore in Iniziare a utilizzare le regole di sicurezza di Firestore.

Installa l'emulatore

Per installare l'emulatore Firestore, utilizza l'interfaccia a riga di comando di Firebase esegui il comando riportato di seguito:

firebase setup:emulators:firestore

Esegui l'emulatore

Inizia inizializzando un progetto Firebase nella directory di lavoro. Si tratta di un primo passaggio comune quando si utilizza l'interfaccia a riga di comando di Firebase.

firebase init

Avvia l'emulatore utilizzando il seguente comando. L'emulatore verrà eseguito fino a quando non interrompi il processo:

firebase emulators:start --only firestore

In molti casi si desidera avviare l'emulatore, eseguire una suite di test e quindi chiudere l'emulatore dopo l'esecuzione dei test. Puoi farlo facilmente utilizzando il comando emulators:exec:

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

Una volta avviato, l'emulatore tenterà di funzionare su una porta predefinita (8080). Puoi cambiare la porta dell'emulatore modificando la sezione "emulators" del file firebase.json:

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

Prima di eseguire l'emulatore

Prima di iniziare a utilizzare l'emulatore, tieni presente quanto segue:

  • L'emulatore caricherà inizialmente le regole specificate nel campo firestore.rules del file firebase.json. Deve essere specificato il nome di un file locale contenente le regole di sicurezza di Firestore, che vengono applicate a tutti i progetti. Se non fornisci il percorso file locale o utilizzi il comando loadFirestoreRules come descritto di seguito, l'emulatore tratta tutti progetti con regole aperte.
  • Anche se la maggior parte degli SDK Firebase funziona direttamente con gli emulatori, solo la libreria @firebase/rules-unit-testing supporta la simulazione di auth nelle regole di sicurezza, semplificando notevolmente i test di unità. Inoltre, la libreria supporta alcune funzionalità specifiche dell'emulatore, come l'eliminazione di tutti i dati, come elencato di seguito.
  • Gli emulatori accetteranno anche i token di autenticazione Firebase di produzione forniti tramite SDK client e valutano di conseguenza le regole, il che consente la connessione la tua applicazione direttamente agli emulatori nei test di integrazione e manuali.

Esegui test locali delle unità

Eseguire test locali delle unità con l'SDK JavaScript 9

Firebase distribuisce una libreria di test delle unità di Regole di sicurezza sia con la relativa versione SDK JavaScript 9 e versione 8 dell'SDK. Le API della libreria sono significativamente diverso. Consigliamo la libreria di test V9, che è più semplice e richiede meno configurazione per connettersi agli emulatori e quindi evita all'uso delle risorse di produzione. Per garantire la compatibilità con le versioni precedenti, la libreria di test v8 disponibile.

Usa il modulo @firebase/rules-unit-testing per interagire con l'emulatore eseguito in locale. Se si verificano timeout o errori ECONNREFUSED, verifica che l'emulatore sia effettivamente in esecuzione.

Ti consigliamo vivamente di utilizzare una versione recente di Node.js per poter utilizzare la notazione async/await. Quasi tutti i comportamenti che potresti voler testare richiedono funzioni asincrone e il modulo di test è progettato per funzionare con il codice basato su promesse.

La libreria di test delle unità delle regole v9 è sempre a conoscenza degli emulatori e non le risorse di produzione.

Importa la libreria utilizzando le istruzioni di importazione modulari della versione 9. Ad esempio:

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.

Dopo l'importazione, l'implementazione dei test delle unità comporta:

  • Creazione e configurazione di un RulesTestEnvironment con una chiamata a initializeTestEnvironment.
  • Configurare i dati di test senza attivare le regole, per praticità che ti consente di ignorarli temporaneamente, RulesTestEnvironment.withSecurityRulesDisabled.
  • Configurare la suite di test e gli hook per test prima/dopo con chiamate a ripulisci i dati e l'ambiente di test, ad esempio RulesTestEnvironment.cleanup() o RulesTestEnvironment.clearFirestore().
  • Implementazione di scenari di test che imitano gli stati di autenticazione utilizzando RulesTestEnvironment.authenticatedContext e RulesTestEnvironment.unauthenticatedContext.

Metodi comuni e funzioni di utilità

Vedi anche i metodi di test specifici dell'emulatore nell'SDK v9.

initializeTestEnvironment() => RulesTestEnvironment

Questa funzione inizializza un ambiente di test per il test delle unità di regole. Chiama per la configurazione di test. Per un'esecuzione corretta, è necessario che gli emulatori siano in esecuzione.

La funzione accetta un oggetto facoltativo che definisce un TestEnvironmentConfig, che può essere costituito da un ID progetto e da impostazioni di configurazione dell'emulatore.

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

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

Questo metodo crea un RulesTestContext, che si comporta come un utente autenticato Utente autenticazione. Alle richieste create tramite il contesto restituito verrà allegato un token di autenticazione simulato. Se vuoi, passa un oggetto che definisce rivendicazioni personalizzate per i payload dei token di autenticazione.

Utilizza l'oggetto contesto test restituito nei test per accedere a eventuali istanze di emulatore configurate, incluse quelle configurate con 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

Questo metodo crea un RulesTestContext, che si comporta come un client che non hanno effettuato l'accesso tramite Authentication. Le richieste create tramite il contesto restituito non avranno token Firebase Auth allegati.

Utilizza l'oggetto di contesto del test restituito nei tuoi test per accedere a qualsiasi emulatore istanze configurate, incluse quelle configurate con 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()

Esegui una funzione di configurazione del test con un contesto che si comporta come se le Regole di sicurezza fossero disabilitate.

Questo metodo prende una funzione di callback, che accetta le regole di sicurezza contesto e restituisce una promessa. Il contesto verrà distrutto una volta che la promessa viene risolta/rifiutata.

RulesTestEnvironment.cleanup()

Questo metodo elimina tutti i RulesTestContexts creati nell'ambiente di test e pulizia delle risorse sottostanti, consentendo un'uscita pulita.

Questo metodo non modifica in alcun modo lo stato degli emulatori. Per reimpostare i dati tra i test, usa il metodo dei dati in chiaro specifico dell'emulatore di applicazioni.

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

Questa è una funzione di utilità per i casi di test.

La funzione afferma che la Promise fornita che racchiude un'operazione dell'emulatore verrà risolta senza violazioni delle regole di sicurezza.

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

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

Questa è una funzione di utilità per i casi di test.

La funzione afferma che la Promise fornita che racchiude un'operazione dell'emulatore verrà rifiutata con una violazione delle regole di sicurezza.

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

Metodi specifici dell'emulatore

Consulta anche i metodi di test e le funzioni di utilità comuni nell'SDK versione 9.

RulesTestEnvironment.clearFirestore() => Promise<void>

Questo metodo cancella i dati nel database Firestore che appartiene al projectId configurato per l'emulatore Firestore.

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

Questo metodo ottiene un'istanza Firestore per il contesto di test. L'istanza dell'SDK client Firebase JS restituita può essere utilizzata con le API SDK client (v9 modulare o v9 compatibile).

Visualizzare le valutazioni delle regole

L'emulatore Firestore ti consente di visualizzare le richieste dei client nell'interfaccia utente di Emulator Suite, incluso il monitoraggio della valutazione per le regole di sicurezza Firebase.

Apri Firestore > Richieste per visualizzare la valutazione dettagliata una sequenza per ogni richiesta.

Monitoraggio delle richieste dell&#39;emulatore Firestore che mostra le valutazioni delle regole di sicurezza

Generare report di test

Dopo aver eseguito una suite di test, puoi accedere ai report sulla copertura dei test che mostrano in che modo è stata valutata ciascuna delle tue regole di sicurezza.

Per ottenere i report, esegui una query su un endpoint esposto sull'emulatore sia in esecuzione. Per una versione adatta ai browser, utilizza il seguente URL:

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

In questo modo, le regole vengono suddivise in espressioni e sottoespressioni su cui puoi eseguire il passaggio del mouse per visualizzare ulteriori informazioni, tra cui il numero di valutazioni e i valori restituiti. Per la versione JSON non elaborata di questi dati, includi il seguente URL nella tua query:

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

Differenze tra l'emulatore e la produzione

  1. Non è necessario creare esplicitamente un progetto Firestore. L'emulatore crea automaticamente tutte le istanze a cui si accede.
  2. L'emulatore Firestore non funziona con il normale flusso di Firebase Authentication. Nell'SDK Firebase Test abbiamo invece fornito il metodo initializeTestApp() nella rules-unit-testing, che richiede un campo auth. L'handle Firebase è stato creato questo metodo si comporterà come se l'autenticazione sia riuscita indipendentemente dall'entità che fornisci. Se passi null, il valore si comporterà come un utente non autenticato (ad esempio, le regole auth != null non andranno a buon fine).

Risolvere i problemi noti

Quando utilizzi l'emulatore Firestore, potresti incontrare i seguenti che le applicazioni presentino problemi di prestazioni. Segui le indicazioni riportate di seguito per risolvere i tuoi comportamenti irregolari in cui ti trovi. Queste note sono scritte tenendo presente la libreria di test di unità delle Regole di sicurezza, ma gli approcci generali sono applicabili a qualsiasi SDK Firebase.

Il comportamento del test non è coerente

Se i test a volte superano e a volte non superano, anche senza modifiche ai test stessi, potrebbe essere necessario verificare che siano sequenziati correttamente. La maggior parte delle interazioni con l'emulatore è asincrona, quindi verifica che tutto il codice asincrono sia sequenziato correttamente. Puoi correggere la sequenza concatenare le promesse o usare liberamente la notazione await.

In particolare, esamina le seguenti operazioni asincrone:

  • Impostazione delle regole di sicurezza, ad esempio con initializeTestEnvironment.
  • Lettura e scrittura di dati, ad esempio con db.collection("users").doc("alice").get().
  • Affermazioni operative, tra cui assertSucceeds e assertFails.

I test passano solo la prima volta che carichi l'emulatore

L'emulatore è stateful. Memorizza tutti i dati scritti in memoria, pertanto tutti i dati andranno persi ogni volta che l'emulatore si arresta. Se esegui più test sullo stesso ID progetto, ogni test può produrre dati che potrebbero influire sui test successivi. Per aggirare questo comportamento, puoi utilizzare uno dei seguenti metodi:

  • Utilizza ID progetto univoci per ogni test. Tieni presente che, se scegli di farlo, dovrai chiamare initializeTestEnvironment nell'ambito di ogni test; le regole vengono caricate automaticamente solo per l'ID progetto predefinito.
  • Ristruttura i test in modo che non interagiscano con i dati scritti in precedenza (ad esempio, utilizza una raccolta diversa per ogni test).
  • Elimina tutti i dati scritti durante un test.

La configurazione del test è molto complicata

Quando configuri il test, ti consigliamo di modificare i dati in un modo non consentito dalle regole di sicurezza di Firestore. Se le regole rendono complessa la configurazione del test, prova a utilizzare RulesTestEnvironment.withSecurityRulesDisabled nei passaggi di configurazione in modo che le letture e le scritture non attivino errori PERMISSION_DENIED.

Dopodiché, il test può eseguire operazioni come utente autenticato o non autenticato utilizzando rispettivamente RulesTestEnvironment.authenticatedContext e unauthenticatedContext. Ciò ti consente di verificare che le regole di sicurezza di Firestore consentano o negano casi diversi.