Questa pagina si basa sui concetti illustrati in
Strutturare le regole di sicurezza e
Scrivere condizioni per le regole di sicurezza per spiegare in che modo
Cloud Firestore Security Rules interagiscono con le query. Esamina più da vicino in che modo
le regole di sicurezza influiscono sulle query che puoi scrivere e descrive come assicurarti che le tue
query utilizzino gli stessi vincoli delle regole di sicurezza. Questa pagina descrive anche
come scrivere regole di sicurezza per consentire o negare le query in base alle proprietà delle query
come limit e orderBy.
Le regole non sono filtri
Quando scrivi query per recuperare documenti, tieni presente che le regole di sicurezza non sono filtri: le query sono tutto o niente. Per risparmiare tempo e risorse, Cloud Firestore valuta una query rispetto al suo potenziale set di risultati anziché ai valori dei campi effettivi di tutti i documenti. Se una query potrebbe potenzialmente restituire documenti che il client non ha l'autorizzazione a leggere, l'intera richiesta non riesce.
Query e regole di sicurezza
Come dimostrano gli esempi riportati di seguito, devi scrivere le query in modo che soddisfino i vincoli delle regole di sicurezza.
Proteggere ed eseguire query sui documenti in base a auth.uid
L'esempio seguente mostra come scrivere una query per recuperare i documenti
protetti da una regola di sicurezza. Considera un database che contiene una raccolta di
story documenti:
/stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
Oltre ai campi title e content, ogni documento memorizza i campi
author e published da utilizzare per il controllo dell'accesso. Questi esempi presuppongono
che l'app utilizzi Firebase Authentication per impostare il campo author sull'UID dell'utente che ha creato il documento. Firebase
Authentication popola anche la variabile request.auth nelle
regole di sicurezza.
La seguente regola di sicurezza utilizza le request.auth e
resource.data variabili per limitare l'accesso in lettura e scrittura di ogni
story al suo autore:
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Supponiamo che la tua app includa una pagina che mostra all'utente un elenco di story
documenti di cui è autore. Potresti aspettarti di poter utilizzare la seguente
query per popolare questa pagina. Tuttavia, questa query non riuscirà perché non include gli stessi vincoli delle regole di sicurezza:
Non valido: i vincoli della query non corrispondono ai vincoli delle regole di sicurezza
// This query will fail
db.collection("stories").get()
La query non riesce anche se l'utente corrente è effettivamente l'autore di ogni
story documento. Il motivo di questo comportamento è che quando
Cloud Firestore applica le regole di sicurezza, valuta la query
rispetto al set di risultati potenziale, non rispetto alle proprietà effettive dei
documenti nel database. Se una query potrebbe potenzialmente includere documenti
che violano le regole di sicurezza, la query non riuscirà.
Al contrario, la seguente query riesce perché include lo stesso
vincolo sul campo author delle regole di sicurezza:
Valido: i vincoli della query corrispondono ai vincoli delle regole di sicurezza
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Proteggere ed eseguire query sui documenti in base a un campo
Per dimostrare ulteriormente l'interazione tra query e regole, le regole di sicurezza
riportate di seguito espandono l'accesso in lettura per la raccolta stories per consentire a qualsiasi utente di
leggere i documenti story in cui il campo published è impostato su true.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
La query per le pagine pubblicate deve includere gli stessi vincoli delle regole di sicurezza rules:
db.collection("stories").where("published", "==", true).get()
Il vincolo della query .where("published", "==", true) garantisce che
resource.data.published sia true per qualsiasi risultato. Pertanto, questa query
soddisfa le regole di sicurezza e può leggere i dati.
Query OR
Quando valuta una query logica OR (or, in o array-contains-any)
rispetto a un set di regole, Cloud Firestore valuta ogni valore di confronto
separatamente. Ogni valore di confronto deve soddisfare i vincoli delle regole di sicurezza. Ad
esempio, per la
seguente regola:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
Non valido: la query non garantisce che
x > 5 per tutti i documenti potenziali
// These queries will fail
query(db.collection("mydocuments"),
or(where("x", "==", 1),
where("x", "==", 6)
)
)
query(db.collection("mydocuments"),
where("x", "in", [1, 3, 6, 42, 99])
)
Valido: la query garantisce che
x > 5 per tutti i documenti potenziali
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
Valutare i vincoli sulle query
Le regole di sicurezza possono anche accettare o negare le query in base ai relativi vincoli.
La variabile request.query contiene le proprietà limit, offset,
e orderBy di una query. Ad esempio, le regole di sicurezza
possono negare qualsiasi query che non limiti il numero massimo di documenti
recuperati a un determinato intervallo:
allow list: if request.query.limit <= 10;
Il seguente set di regole mostra come scrivere regole di sicurezza che valutano
i vincoli applicati alle query. Questo esempio espande il set di regole stories
precedente con le seguenti modifiche:
- Il set di regole separa la regola di lettura in regole per
getelist. - La regola
getlimita il recupero di singoli documenti ai documenti pubblici o a i documenti di cui l'utente è autore. - La regola
listapplica le stesse restrizioni diget, ma per le query. Controlla anche il limite della query, quindi nega qualsiasi query senza limite o con un limite superiore a 10. - Il set di regole definisce una funzione
authorOrPublished()per evitare la duplicazione del codice.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
Query dei gruppi di raccolte e regole di sicurezza
Per impostazione predefinita, le query sono limitate a una singola raccolta e recuperano i risultati solo da quella raccolta. Con le query dei gruppi di raccolte, puoi recuperare i risultati da un gruppo di raccolte composto da tutte le raccolte con lo stesso ID. Questa sezione descrive come proteggere le query dei gruppi di raccolte utilizzando le regole di sicurezza.
Proteggere ed eseguire query sui documenti in base ai gruppi di raccolte
Nelle regole di sicurezza, devi consentire esplicitamente le query dei gruppi di raccolte scrivendo una regola per il gruppo di raccolte:
- Assicurati che
rules_version = '2';sia la prima riga del set di regole. Le query dei gruppi di raccolte richiedono il nuovo comportamento del carattere jolly ricorsivo{name=**}della versione 2 delle regole di sicurezza. - Scrivi una regola per il gruppo di raccolte utilizzando
match /{path=**}/[COLLECTION_ID]/{doc}.
Ad esempio, considera un forum organizzato in forum documenti contenenti
posts sottoraccolte:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
In questa applicazione, rendiamo i post modificabili dai relativi proprietari e leggibili dagli utenti autenticati:
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Qualsiasi utente autenticato può recuperare i post di un singolo forum:
db.collection("forums/technology/posts").get()
Ma cosa succede se vuoi mostrare all'utente corrente i suoi post su tutti i forum?
Puoi utilizzare una query dei gruppi di raccolte per recuperare
i risultati da tutte le raccolze posts:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
Nelle regole di sicurezza, devi consentire questa query scrivendo una regola di lettura o di elenco per il posts gruppo di raccolte:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Tieni presente, tuttavia, che queste regole si applicheranno a tutte le raccolte con ID posts,
indipendentemente dalla gerarchia. Ad esempio, queste regole si applicano a tutte le seguenti
posts raccolte:
/posts/{postid}/forums/{forumid}/posts/{postid}/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Proteggere le query dei gruppi di raccolte in base a un campo
Come le query a singola raccolta, anche le query dei gruppi di raccolte devono soddisfare i
vincoli impostati dalle regole di sicurezza. Ad esempio, possiamo aggiungere un campo published
a ogni post del forum, come abbiamo fatto nell'esempio stories riportato sopra:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
Possiamo quindi scrivere regole per il gruppo di raccolte posts in base allo stato
published e al post author:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
Con queste regole, i client web, Apple e Android possono eseguire le seguenti query:
Chiunque può recuperare i post pubblicati in un forum:
db.collection("forums/technology/posts").where('published', '==', true).get()Chiunque può recuperare i post pubblicati di un autore su tutti i forum:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()Gli autori possono recuperare tutti i loro post pubblicati e non pubblicati su tutti i forum:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Proteggere ed eseguire query sui documenti in base al gruppo di raccolte e al percorso del documento
In alcuni casi, potresti voler limitare le query dei gruppi di raccolte in base al percorso del documento. Per creare queste restrizioni, puoi utilizzare le stesse tecniche per proteggere ed eseguire query sui documenti in base a un campo.
Considera un'applicazione che tiene traccia delle transazioni di ogni utente tra diversi scambi di azioni e criptovalute:
/users/{userid}/exchange/{exchangeid}/transactions/{transaction}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
Nota il campo user. Anche se sappiamo a quale utente appartiene un transaction
documento dal percorso del documento, duplichiamo queste informazioni in ogni
transaction documento perché ci consente di fare due cose:
Scrivere query dei gruppi di raccolte limitate ai documenti che includono un
/users/{userid}specifico nel percorso del documento. Ad esempio:var user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)Applicare questa restrizione a tutte le query sul
transactionsgruppo di raccolte in modo che un utente non possa recuperare i documentitransactiondi un altro utente.
Applichiamo questa restrizione nelle regole di sicurezza e includiamo la convalida dei dati
per il user campo:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
Passaggi successivi
- Per un esempio più dettagliato del controllo dell'accesso basato sui ruoli, vedi Proteggere l'accesso ai dati per utenti e gruppi.
- Leggi il riferimento alle regole di sicurezza.