Test delle regole di sicurezza
Durante la creazione dell'app, potresti bloccare l'accesso al tuo databaseFirestore. Tuttavia, prima del lancio avrai bisogno di regole di sicurezza firewall più specifiche. Con l'emulatore Firestore, oltre a prototipare e testare le funzionalità e comportamenti generali dell'app, puoi scrivere test di unità che verificano il comportamento delle regole di sicurezza di Firestore.
Guida rapida
Per alcuni scenari di test di base con regole semplici, prova l'esempio di guida rapida.
Comprendi le regole di sicurezza di Firestore
Implementa le regole di sicurezza di Firebase Authentication e Firestore per l'autenticazione serverless, l'autorizzazione e la convalida dei dati quando utilizzi le librerie client per dispositivi mobili e web.
Le regole di sicurezza di Firestore includono due elementi:
- Istruzione
match
che identifica i documenti nel database. - Un'espressione
allow
che controlla l'accesso a tali documenti.
Firebase Authentication verifica le credenziali degli utenti e fornisce le basi per sistemi di accesso basati sugli utenti e sui ruoli.
Ogni richiesta di database da una libreria client per dispositivi mobili/web di Firestore viene valutata in base alle regole di sicurezza prima di leggere o scrivere dati. Se le regole negano l'accesso a uno dei percorsi del documento specificati, l'intera richiesta non riesce.
Scopri di più sulle regole di sicurezza Firestore nella Guida introduttiva alle regole di sicurezza Firestore.
Installa l'emulatore
Per installare l'emulatore Firestore, utilizza l'interfaccia a riga di comando di Firebase ed esegui il comando seguente:
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 finché non completerai la procedura:
firebase emulators:start --only firestore
In molti casi vuoi avviare l'emulatore, eseguire una suite di test e poi arrestare l'emulatore dopo l'esecuzione dei test. Puoi farlo facilmente usando il comando
emulators:exec
:
firebase emulators:exec --only firestore "./my-test-script.sh"
All'avvio, l'emulatore tenterà di eseguire l'esecuzione su una porta predefinita (8080). Per cambiare la porta dell'emulatore, modifica 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 filefirebase.json
. Prevede il nome di un file locale contenente le regole di sicurezza Firestore e le applica a tutti i progetti. Se non fornisci il percorso del file locale o se utilizzi il metodoloadFirestoreRules
come descritto di seguito, l'emulatore considera tutti i progetti come regole aperte. - Sebbene
la maggior parte degli SDK Firebase
funzioni direttamente con gli emulatori, solo la libreria
@firebase/rules-unit-testing
supporta la simulazione diauth
nelle regole di sicurezza, rendendo molto più semplice il test delle unità. Inoltre, la libreria supporta alcune funzionalità specifiche dell'emulatore, come la cancellazione di tutti i dati, come indicato di seguito. - Gli emulatori accettano anche token Firebase Auth di produzione forniti tramite gli SDK client e valutano le regole di conseguenza, consentendo la connessione della tua applicazione direttamente agli emulatori nei test di integrazione e manuali.
Test dei test locali delle unità
Eseguire test delle unità locali con l'SDK JavaScript v9
Firebase distribuisce una libreria di test delle unità di Regole di sicurezza con il suo SDK JavaScript versione 9 e il suo SDK versione 8. Le API delle librerie sono molto diverse. Consigliamo la libreria di test v9, che è più semplice e richiede meno configurazione per il collegamento agli emulatori, evitando così l'uso accidentale delle risorse di produzione. Per la compatibilità con le versioni precedenti, continuiamo a rendere disponibile la libreria di test v8.
- Metodi di test comuni e funzioni di utilità nell'SDK v9
- Metodi di test specifici dell'emulatore nell'SDK v9
Utilizza il modulo @firebase/rules-unit-testing
per interagire con l'emulatore
eseguito localmente. Se vengono visualizzati timeout o errori ECONNREFUSED
, verifica
che l'emulatore sia effettivamente in esecuzione.
Ti consigliamo vivamente di utilizzare una versione recente di Node.js, in modo da poter utilizzare la notazione async/await
. Quasi tutto il comportamento che potresti voler testare
comprende funzioni asincrone e il modulo di test è progettato per funzionare con
codice basato su promise.
La libreria Test v9 Rules Unit è sempre a conoscenza degli emulatori e non tocca mai le risorse di produzione.
Puoi importare la libreria utilizzando istruzioni di importazione modulari v9. Ad esempio:
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.
Una volta eseguita l'importazione, l'implementazione dei test delle unità comporta:
- Creazione e configurazione di un
RulesTestEnvironment
con chiamata ainitializeTestEnvironment
. - Configura i dati di test senza attivare le regole, utilizzando un metodo
di convenienza che ti consente di ignorarle temporaneamente,
RulesTestEnvironment.withSecurityRulesDisabled
. - Configurazione di una suite di test e di test prima/dopo con cicli di chiamata per pulire i dati e l'ambiente di test, come
RulesTestEnvironment.cleanup()
oRulesTestEnvironment.clearFirestore()
. - Implementazione di scenari di test che imitano gli stati di autenticazione utilizzando
RulesTestEnvironment.authenticatedContext
eRulesTestEnvironment.unauthenticatedContext
.
Metodi comuni e funzioni di utilità
Consulta anche i metodi di test specifici dell'emulatore nell'SDK v9.
initializeTestEnvironment() => RulesTestEnvironment
Questa funzione inizializza un ambiente di test per il test dell'unità regole. Chiama prima questa funzione per la configurazione del test. Per l'esecuzione corretta è necessario che gli emulatori siano in esecuzione.
La funzione accetta un oggetto facoltativo che definisce un elemento TestEnvironmentConfig
,
che può essere costituito da un ID progetto e dalle 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 di Authentication autenticato. Alle richieste create tramite il contesto restituito verrà allegato un token di autenticazione fittizio. Facoltativamente, passa un oggetto che definisce le attestazioni personalizzate o
le sostituzioni dei payload del token di autenticazione.
Utilizza l'oggetto di contesto restituito nei test per accedere a qualsiasi istanza di emulatore configurata, 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 ha eseguito l'accesso tramite Authentication. Alle richieste create tramite il contesto restituito
non verranno associati i token di Firebase Auth.
Utilizza l'oggetto di contesto restituito nei test per accedere a qualsiasi istanza di emulatore configurata, 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 di test con un contesto che si comporti come se le regole di sicurezza fossero state disattivate.
Questo metodo prevede una funzione di callback, in cui il contesto delle regole di sicurezza viene ignorato e viene restituita una promessa. Il contesto verrà eliminato una volta che la promessa verrà risolta / rifiutata.
RulesTestEnvironment.cleanup()
Questo metodo elimina tutti i RulesTestContexts
creati nell'ambiente di test e
pulisce le risorse sottostanti, consentendo un'uscita pulita.
Questo metodo non modifica in alcun modo lo stato degli emulatori. Per reimpostare i dati tra un test e l'altro, utilizza il metodo chiaro e chiaro specifico dell'applicazione.
assertSucceeds(pr: Promise<any>)) => Promise<any>
Questa è una funzione di utilità di test.
La funzione afferma che l'offerta Promise che esegue 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à di test.
La funzione afferma che l'offerta Promise che esegue 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 comuni e le funzioni di utilità nell'SDK v9.
RulesTestEnvironment.clearFirestore() => Promise<void>
Questo metodo cancella i dati nel database Firestore che appartengono all'projectId
configurato per l'emulatore Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
Questo metodo riceve un'istanza Firestore per questo contesto di test. L'istanza SDK Firebase JS restituita può essere utilizzata con le API client SDK (v9 modulare o v9 compat).
Visualizza le valutazioni delle regole
L'emulatore Firestore consente di visualizzare le richieste del client nell'interfaccia utente di Emulator Suite, compreso il tracciamento di valutazione per le regole di sicurezza Firebase.
Apri la scheda Richieste Floodlight per visualizzare la sequenza di valutazione dettagliata per ogni richiesta.
Generare report di test
Dopo aver eseguito una suite di test, puoi accedere ai rapporti sulla copertura di test che mostrano come è stata valutata ciascuna delle tue regole di sicurezza.
Per ottenere i rapporti, esegui una query su un endpoint esposto sull'emulatore mentre è in esecuzione. Per una versione ottimizzata per i browser, utilizza il seguente URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
Suddivide le regole in espressioni e sottoespressioni che puoi spostare con il mouse per ottenere ulteriori informazioni, tra cui il numero di valutazioni e 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 emulatore e produzione
- Non devi creare esplicitamente un progetto Firestore. L'emulatore crea automaticamente qualsiasi istanza a cui si accede.
- L'emulatore Firestore non funziona con il normale flusso di autenticazione Firebase.
Nell'SDK Firebase Test abbiamo invece fornito il metodo
initializeTestApp()
nella libreriarules-unit-testing
, che utilizza un campoauth
. L'handle di Firebase creato con questo metodo si comporterà come se fosse stato autenticato correttamente come qualsiasi altra entità tu abbia fornito. Se trasmetti innull
, si comporterà come un utente non autenticato (ad esempio, le regoleauth != null
non andranno a buon fine).
Risolvere i problemi noti
Durante l'utilizzo dell'emulatore Firestore, potresti riscontrare i seguenti problemi noti. Segui le indicazioni riportate di seguito per risolvere eventuali comportamenti irregolari. Queste note sono scritte in base alla libreria di test dell'unità di regole di sicurezza, ma gli approcci generali sono applicabili a qualsiasi SDK Firebase.
Il comportamento dei test è incoerente
Se a volte i test hanno esito positivo e non superato, anche senza modifiche, è possibile che tu debba verificare che siano in sequenza correttamente.
La maggior parte delle interazioni con l'emulatore è asincrona, pertanto verifica che tutto il codice asincrono sia in sequenza corretta. Puoi correggere la sequenza seguendo le promesse o utilizzando la notazione await
in modo liberale.
In particolare, rivedi le seguenti operazioni asincrone:
- Impostazione di regole di sicurezza, ad esempio
initializeTestEnvironment
. - Lettura e scrittura di dati, ad esempio
db.collection("users").doc("alice").get()
. - Asserzioni operative, tra cui
assertSucceeds
eassertFails
.
I test vengono superati solo la prima volta che carichi l'emulatore
L'emulatore è stateful. Archivia tutti i dati scritti in memoria, quindi tutti i dati andranno persi ogni volta che l'emulatore si spegne. Se stai eseguendo più test sullo stesso ID progetto, ogni test può produrre dati che potrebbero influire sui test successivi. Puoi utilizzare uno dei seguenti metodi per aggirare questo comportamento:
- Utilizza ID progetto univoci per ogni test. Tieni presente che, se scegli di farlo, dovrai chiamare
initializeTestEnvironment
come parte di ogni test; le regole vengono caricate automaticamente solo per l'ID progetto predefinito. - Riorganizza i test in modo che non interagiscano con i dati scritti in precedenza (ad esempio, utilizza una raccolta diversa per ogni test).
- Eliminare tutti i dati scritti durante un test.
La configurazione del test è molto complicata
Quando configuri il test, ti consigliamo di modificare i dati in modo che le regole di sicurezza di firewall non consentano effettivamente di farlo. Se le regole rendono la configurazione di test complessa, prova a utilizzare RulesTestEnvironment.withSecurityRulesDisabled
nei passaggi di configurazione, quindi le operazioni di lettura e scrittura non attiveranno errori PERMISSION_DENIED
.
Successivamente, il test può eseguire le operazioni in qualità di utente autenticato o non autenticato utilizzando RulesTestEnvironment.authenticatedContext
e unauthenticatedContext
. In questo modo puoi verificare che le regole di sicurezza di Firestore consentano / negano correttamente le diverse richieste.