Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Testa le regole di sicurezza di Cloud Firestore

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Mentre crei la tua app, potresti voler bloccare l'accesso al database di Cloud Firestore. Tuttavia, prima del lancio, avrai bisogno di regole di sicurezza Cloud Firestore più dettagliate. Con l'emulatore Cloud Firestore, oltre a creare prototipi e testare le funzionalità e il comportamento generali della tua app, puoi scrivere unit test che controllano il comportamento delle tue regole di sicurezza di Cloud Firestore.

Avvio veloce

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

Comprendi le regole di sicurezza di Cloud Firestore

Implementa l'autenticazione Firebase e le regole di sicurezza di Cloud Firestore per l'autenticazione serverless, l'autorizzazione e la convalida dei dati quando utilizzi le librerie dei client mobili e Web.

Le regole di sicurezza di Cloud Firestore includono due parti:

  1. Una dichiarazione di match che identifica i documenti nel database.
  2. Un'espressione di allow che controlla l'accesso a tali documenti.

Firebase Authentication verifica le credenziali degli utenti e fornisce le basi per i sistemi di accesso basati sugli utenti e sui ruoli.

Ogni richiesta di database da una libreria client mobile/web di Cloud Firestore viene valutata rispetto alle tue regole di sicurezza prima di leggere o scrivere qualsiasi dato. Se le regole negano l'accesso a uno qualsiasi dei percorsi del documento specificati, l'intera richiesta non riesce.

Scopri di più sulle regole di sicurezza di Cloud Firestore in Inizia con le regole di sicurezza di Cloud Firestore .

Installa l'emulatore

Per installare l'emulatore Cloud 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 tua directory di lavoro. Questo è un primo passaggio comune quando si utilizza l'interfaccia a riga di comando di Firebase .

firebase init

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

firebase emulators:start --only firestore

In molti casi si desidera avviare l'emulatore, eseguire una suite di test e quindi spegnere l'emulatore dopo l'esecuzione dei test. Puoi farlo facilmente usando 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 tuo 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 . Si aspetta il nome di un file locale contenente le regole di sicurezza di Cloud Firestore e applica tali regole a tutti i progetti. Se non si fornisce il percorso del file locale o si utilizza il metodo loadFirestoreRules come descritto di seguito, l'emulatore considera tutti i progetti come se avessero regole aperte.
  • Sebbene la maggior parte degli SDK Firebase funzioni direttamente con gli emulatori, solo la @firebase/rules-unit-testing supporta l' auth fittizia nelle regole di sicurezza, rendendo molto più semplici gli unit test. Inoltre, la libreria supporta alcune funzionalità specifiche dell'emulatore come la cancellazione di tutti i dati, come elencato di seguito.
  • Gli emulatori accetteranno anche i token Firebase Auth di produzione forniti tramite gli SDK client e valuteranno le regole di conseguenza, il che consente di collegare l'applicazione direttamente agli emulatori in integrazione e test manuali.

Esegui test di unità locali

Esegui test di unità locali con l'SDK JavaScript v9

Firebase distribuisce una libreria di unit test delle regole di sicurezza con l'SDK JavaScript versione 9 e l'SDK versione 8. Le API della libreria sono significativamente diverse. Consigliamo la libreria di test v9, che è più snella e richiede meno configurazione per connettersi agli emulatori ed evitare così in sicurezza l'uso accidentale delle risorse di produzione. Per la compatibilità con le versioni precedenti, continuiamo a rendere disponibile la libreria di test v8 .

Usa il @firebase/rules-unit-testing per interagire con l'emulatore che viene eseguito localmente. Se ricevi timeout o errori ECONNREFUSED , ricontrolla che l'emulatore sia effettivamente in esecuzione.

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 coinvolge funzioni asincrone e il modulo di test è progettato per funzionare con codice basato su Promise.

La libreria v9 Rules Unit Testing è sempre a conoscenza degli emulatori e non tocca mai le tue risorse di produzione.

Importare la libreria utilizzando le istruzioni di importazione modulari v9. Per 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 importati, l'implementazione degli unit test comporta:

  • Creazione e configurazione di un RulesTestEnvironment con una chiamata a initializeTestEnvironment .
  • Configurazione dei dati di test senza attivare le regole, utilizzando un metodo pratico che consente di ignorarle temporaneamente, RulesTestEnvironment.withSecurityRulesDisabled .
  • Configurazione della suite di test e degli hook per test prima/dopo con chiamate per ripulire i dati e l'ambiente di test, come RulesTestEnvironment.cleanup() o RulesTestEnvironment.clearFirestore() .
  • Implementazione di casi di test che imitano gli stati di autenticazione usando 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à delle regole. Chiamare prima questa funzione per la configurazione di prova. L'esecuzione riuscita richiede 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 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 autenticazione autenticato. Le richieste create tramite il contesto restituito avranno un token di autenticazione fittizio allegato. Facoltativamente, passare un oggetto che definisce attestazioni o sostituzioni personalizzate per i payload del token di autenticazione.

Utilizzare l'oggetto contesto di test restituito nei test per accedere a qualsiasi istanza dell'emulatore configurata, comprese 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 effettuato l'accesso tramite l'autenticazione. Le richieste create tramite il contesto restituito non avranno token Firebase Auth allegati.

Utilizzare l'oggetto contesto di test restituito nei test per accedere a qualsiasi istanza dell'emulatore configurata, comprese 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()

Eseguire una funzione di configurazione di prova con un contesto che si comporta come se le regole di sicurezza fossero disabilitate.

Questo metodo accetta una funzione di callback, che accetta il contesto di bypass delle regole di sicurezza e restituisce una promessa. Il contesto verrà distrutto una volta che la promessa sarà risolta/rifiutata.

RulesTestEnvironment.cleanup()

Questo metodo distrugge tutti i RulesTestContexts creati nell'ambiente di test e ripulisce le risorse sottostanti, consentendo un'uscita pulita.

Questo metodo non modifica in alcun modo lo stato degli emulatori. Per reimpostare i dati tra i test, utilizzare il metodo Clear Data specifico dell'emulatore dell'applicazione.

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

Questa è una funzione di utilità del test case.

La funzione afferma che la promessa fornita che avvolge un'operazione di 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à del test case.

La funzione afferma che la promessa fornita che avvolge un'operazione di 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 appartiene al projectId configurato per l'emulatore Firestore.

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

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

Visualizza le valutazioni delle regole

L'emulatore Cloud Firestore ti consente di visualizzare le richieste dei client nell'interfaccia utente di Emulator Suite, inclusa la traccia di valutazione per le regole di sicurezza Firebase.

Aprire la scheda Firestore > Richieste per visualizzare la sequenza di valutazione dettagliata per ciascuna richiesta.

Monitoraggio delle richieste dell'emulatore Firestore che mostra le valutazioni delle regole di sicurezza

Genera rapporti di prova

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

Per ottenere i report, esegui una query su un endpoint esposto sull'emulatore mentre è in esecuzione. Per una versione compatibile con browser, utilizzare il seguente URL:

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

Questo suddivide le tue regole in espressioni e sottoespressioni che puoi passare con il mouse per ulteriori informazioni, incluso il numero di valutazioni e valori restituiti. Per la versione JSON grezza 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 Cloud Firestore. L'emulatore crea automaticamente qualsiasi istanza a cui si accede.
  2. L'emulatore Cloud Firestore non funziona con il normale flusso di autenticazione Firebase. Invece, in Firebase Test SDK, abbiamo fornito il metodo initializeTestApp() nella libreria rules-unit-testing , che accetta un campo auth . L'handle Firebase creato utilizzando questo metodo si comporterà come se fosse stato autenticato correttamente come qualsiasi entità fornita. Se si passa null , si comporterà come un utente non autenticato ( auth != null falliranno, ad esempio).

Risolvi i problemi noti

Quando utilizzi l'emulatore Cloud Firestore, potresti riscontrare i seguenti problemi noti. Segui le indicazioni riportate di seguito per risolvere eventuali comportamenti irregolari che stai riscontrando. Queste note sono state scritte tenendo presente la libreria di unit test delle regole di sicurezza, ma gli approcci generali sono applicabili a qualsiasi SDK Firebase.

Il comportamento del test è incoerente

Se occasionalmente i test superano e falliscono, anche senza alcuna modifica ai test stessi, potrebbe essere necessario verificare che siano sequenziati correttamente. La maggior parte delle interazioni con l'emulatore sono asincrone, quindi ricontrolla che tutto il codice asincrono sia sequenziato correttamente. Puoi correggere la sequenza concatenando le promesse o usando 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 db.collection("users").doc("alice").get() .
  • Affermazioni operative, inclusi assertSucceeds e assertFails .

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

L'emulatore è con stato. Memorizza tutti i dati scritti su di esso in memoria, quindi tutti i dati vengono persi ogni volta che l'emulatore si spegne. Se stai eseguendo più test sullo stesso ID progetto, ogni test può produrre dati che potrebbero influenzare i test successivi. È possibile utilizzare uno dei seguenti metodi per aggirare questo comportamento:

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

La configurazione del test è molto complicata

Quando imposti il ​​test, potresti voler modificare i dati in un modo che le regole di sicurezza di Cloud Firestore non consentono effettivamente. Se le tue 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 attiveranno errori PERMISSION_DENIED .

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