Questa guida si basa sulla guida alla strutturazione delle regole di sicurezza per mostrare come aggiungere condizioni al Cloud Firestore Security Rules. Se non hai familiarità con le nozioni di base di Cloud Firestore Security Rules, consulta la guida Introduzione.
L'elemento costitutivo principale di Cloud Firestore Security Rules è la condizione. Una condizione è un'espressione booleana che determina se una determinata operazione deve essere consentita o negata. Utilizza le regole di sicurezza per scrivere condizioni che controllino l'autenticazione utente, convalidino i dati in entrata o addirittura accedano ad altre parti del database.
Autenticazione
Uno dei pattern di regole di sicurezza più comuni è il controllo dell'accesso in base allo stato di autenticazione dell'utente. Ad esempio, la tua app potrebbe voler consentire solo agli utenti che hanno eseguito l'accesso di scrivere dati:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to access documents in the "cities" collection
// only if they are authenticated.
match /cities/{city} {
allow read, write: if request.auth != null;
}
}
}
Un altro pattern comune è assicurarsi che gli utenti possano leggere e scrivere solo i propri dati:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
Se la tua app utilizza Firebase Authentication o Google Cloud Identity Platform, la variabile request.auth
contiene le informazioni di autenticazione per il client che richiede i dati.
Per ulteriori informazioni su request.auth
, consulta la documentazione di riferimento.
Convalida dei dati
Molte app archiviano le informazioni sul controllo dell'accesso come campi nei documenti del database. Cloud Firestore Security Rules può consentire o negare dinamicamente l'accesso in base ai dati del documento:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
match /cities/{city} {
allow read: if resource.data.visibility == 'public';
}
}
}
La variabile resource
fa riferimento al documento richiesto e resource.data
è
una mappa di tutti i campi e i valori memorizzati nel documento. Per ulteriori informazioni sulla variabile resource
, consulta la documentazione di riferimento.
Quando scrivi i dati, potresti voler confrontare i dati in entrata con quelli esistenti.
In questo caso, se il tuo insieme di regole consente la scrittura in attesa, la variabile request.resource
contiene lo stato futuro del documento. Per le operazioni update
che modificano solo un sottoinsieme di campi del documento, la variabile request.resource
conterrà lo stato del documento in attesa dopo l'operazione. Puoi controllare i valori dei campi in request.resource
per evitare aggiornamenti dei dati indesiderati o incoerenti:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure all cities have a positive population and
// the name is not changed
match /cities/{city} {
allow update: if request.resource.data.population > 0
&& request.resource.data.name == resource.data.name;
}
}
}
Accedere ad altri documenti
Utilizzando le funzioni get()
e exists()
, le regole di sicurezza possono valutare le richieste in arrivo in base ad altri documenti nel database. Le funzioni get()
e
exists()
prevedono entrambe percorsi dei documenti completamente specificati. Quando utilizzi
variabili per creare percorsi per get()
e exists()
, devi eseguire esplicitamente
la codifica delle variabili utilizzando la sintassi $(variable)
.
Nell'esempio seguente, la variabile database
viene acquisita dall'istruzione match /databases/{database}/documents
di corrispondenza e utilizzata per formare il percorso:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
// Make sure a 'users' document exists for the requesting user before
// allowing any writes to the 'cities' collection
allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid));
// Allow the user to delete cities if their user document has the
// 'admin' field set to 'true'
allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
}
}
}
Per le scritture, puoi utilizzare la funzione getAfter()
per accedere allo stato di un
documento al termine di una transazione o di un batch di scritture, ma prima dell'commit della transazione o del batch. Come get()
, la funzione getAfter()
accetta un
percorso del documento completamente specificato. Puoi utilizzare getAfter()
per definire insiemi di scritture
che devono avvenire insieme come transazione o batch.
Limiti di accesso alle chiamate
Esiste un limite per le chiamate di accesso ai documenti per valutazione dell'insieme di regole:
- 10 per richieste di documenti singoli e di query.
-
20 per transazioni, operazioni di scrittura in batch e operazioni di lettura di più documenti. A ciascuna operazione si applica anche il limite precedente di 10.
Ad esempio, immagina di creare una richiesta di scrittura in batch con 3 operazioni di scrittura e che le tue regole di sicurezza utilizzino 2 chiamate di accesso ai documenti per convalidare ogni operazione di scrittura. In questo caso, ogni operazione di scrittura utilizza 2 delle sue 10 chiamate di accesso e la richiesta di scrittura in batch utilizza 6 delle sue 20 chiamate di accesso.
Il superamento di uno dei limiti comporta un errore di autorizzazione negata. Alcune chiamate di accesso ai documenti possono essere memorizzate nella cache e le chiamate nella cache non vengono considerate ai fini dei limiti.
Per una spiegazione dettagliata di come questi limiti influiscono sulle transazioni e sulle scritture collettive, consulta la guida per la protezione delle operazioni atomiche.
Accedere alle chiamate e ai prezzi
L'utilizzo di queste funzioni esegue un'operazione di lettura nel database, il che significa che ti verrà addebitato il costo della lettura dei documenti anche se le regole rifiutano la richiesta. Per informazioni di fatturazione più specifiche, consulta la pagina Cloud Firestore Prezzi.
Funzioni personalizzate
Man mano che le regole di sicurezza diventano più complesse, ti consigliamo di racchiudere insiemi di condizioni in funzioni che puoi riutilizzare nel set di regole. Le regole di sicurezza supportano le funzioni personalizzate. La sintassi delle funzioni personalizzate è un po' simile a quella di JavaScript, ma le funzioni delle regole di sicurezza sono scritte in un linguaggio specifico per dominio con alcune limitazioni importanti:
- Le funzioni possono contenere una sola istruzione
return
. Non possono contenere alcuna logica aggiuntiva. Ad esempio, non possono eseguire loop o chiamare servizi esterni. - Le funzioni possono accedere automaticamente alle funzioni e alle variabili dall'ambito
in cui sono definite. Ad esempio, una funzione definita all'interno
dell'ambito
service cloud.firestore
ha accesso alla variabileresource
e alle funzioni incorporate comeget()
eexists()
. - Le funzioni possono chiamare altre funzioni, ma non possono essere ricorsive. La profondità totale della pila di chiamate è limitata a 10.
- Nella versione delle regole
v2
, le funzioni possono definire variabili utilizzando la parola chiavelet
. Le funzioni possono avere fino a 10 associazioni let, ma devono terminare con un'istruzione return.
Una funzione è definita con la parola chiave function
e accetta zero o più argomenti. Ad esempio, potresti voler combinare i due tipi di condizioni utilizzati
gli esempi precedenti in un'unica funzione:
service cloud.firestore {
match /databases/{database}/documents {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /cities/{city} {
allow read, write: if signedInOrPublic();
}
match /users/{user} {
allow read, write: if signedInOrPublic();
}
}
}
L'utilizzo di funzioni nelle regole di sicurezza le rende più gestibili man mano che la complessità delle regole aumenta.
Le regole non sono filtri
Dopo aver protetto i dati e aver iniziato a scrivere query, tieni presente che le regole di sicurezza non sono filtri. Non puoi scrivere una query per tutti i documenti di una raccolta e aspettarti che Cloud Firestore restituisca solo i documenti a cui il client corrente ha l'autorizzazione di accesso.
Ad esempio, prendi in considerazione la seguente regola di sicurezza:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
match /cities/{city} {
allow read: if resource.data.visibility == 'public';
}
}
}
Rifiutato: questa regola rifiuta la seguente query perché il set di risultati può includere documenti in cui visibility
non è public
:
Web
db.collection("cities").get() .then(function(querySnapshot) { querySnapshot.forEach(function(doc) { console.log(doc.id, " => ", doc.data()); }); });
Consentito: questa regola consente la seguente query perché la clausola where("visibility", "==", "public")
garantisce che il set di risultati soddisfi la condizione della regola:
Web
db.collection("cities").where("visibility", "==", "public").get() .then(function(querySnapshot) { querySnapshot.forEach(function(doc) { console.log(doc.id, " => ", doc.data()); }); });
Le regole di sicurezza di Cloud Firestore valutano ogni query in base al suo potenziale risultato e non completano la richiesta se potrebbe restituire un documento per la lettura del quale il client non ha l'autorizzazione. Le query devono rispettare le limitazioni impostate dalle tue regole di sicurezza. Per saperne di più su query e regole di sicurezza, consulta Eseguire query sui dati in modo sicuro.
Passaggi successivi
- Scopri in che modo le regole di sicurezza influiscono sulle query.
- Scopri come strutturare le regole di sicurezza.
- Leggi il riferimento alle regole di sicurezza.
- Per le app che utilizzano Cloud Storage for Firebase, scopri come scrivere condizioniCloud Storage Security Rules che accedono ai documenti Cloud Firestore.