Questa pagina si basa sui concetti di
Strutturare le regole di sicurezza e
Scrivere le condizioni per le Regole di sicurezza per spiegare come
Cloud Firestore Security Rules interagiscono con le query. Esamina meglio il modo in cui
le regole di sicurezza influiscono sulle query che puoi scrivere e descrive come garantire
usano gli stessi vincoli delle tue regole di sicurezza. Anche in questa pagina
descrive come scrivere regole di sicurezza per consentire o negare le query in base
proprietà come limit
e orderBy
.
Le regole non sono filtri
Quando scrivi query per recuperare i documenti, tieni presente che le regole di sicurezza non filtri: le query sono tutte o niente. Per risparmiare tempo e risorse, Cloud Firestore valuta una query in base al potenziale set di risultati anziché i valori effettivi dei campi per tutti i tuoi documenti. Se una query potesse potrebbero restituire documenti che il client non dispone dell'autorizzazione di lettura, l'intera richiesta non va a buon fine.
Query e regole di sicurezza
Come dimostrano gli esempi di seguito, è necessario scrivere le query per adattarle al i vincoli delle tue regole di sicurezza.
Proteggi e interroga documenti basati su auth.uid
L'esempio seguente mostra come scrivere una query per recuperare documenti
protette da una regola di sicurezza. Considera un database che contiene una raccolta
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
l'app usa Firebase Authentication per impostare il campo author
all'UID dell'utente che ha creato il documento. Firebase
L'autenticazione inserisce anche la variabile request.auth
in
le regole di sicurezza.
La seguente regola di sicurezza utilizza le variabili request.auth
e
resource.data
per limitare l'accesso in lettura e scrittura per 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 da loro creati. Potresti aspettarti di usare i seguenti
per compilare questa pagina. Tuttavia, questa query avrà esito negativo perché non
includono gli stessi vincoli delle regole di sicurezza:
Non valido: i vincoli delle query non corrispondono vincoli delle regole di sicurezza
// This query will fail
db.collection("stories").get()
La query ha esito negativo 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 e valuta la query
rispetto al suo insieme di risultati potenziali, non rispetto alle proprietà effettive di
documenti presenti nel database. Se una query potrebbe potenzialmente includere documenti che violano le tue regole di sicurezza, la query non andrà a buon fine.
Al contrario, la seguente query ha esito positivo perché include lo stesso vincolo sul campo author
delle regole di sicurezza:
Valido: i vincoli delle query corrispondono alla sicurezza vincoli delle regole
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,
regole riportate di seguito espandono l'accesso in lettura per la raccolta stories
in modo da consentire a qualsiasi utente di
lettura di story
documenti 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 del livello di sicurezza regole:
db.collection("stories").where("published", "==", true).get()
La limitazione della query .where("published", "==", true)
garantisce che
resource.data.published
sia true
per qualsiasi risultato. Pertanto, questa query
soddisfi le regole di sicurezza e
può leggere i dati.
OR
query
Durante la valutazione di 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. Per
ad esempio, per
regola seguente:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
Non valido: la query non garantisce che
x > 5
per tutti i potenziali documenti
// 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 potenziali documenti
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
Valutazione dei vincoli sulle query
Le regole di sicurezza possono anche accettare o rifiutare 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
può rifiutare qualsiasi query che non limita il numero massimo di documenti
recuperate in un determinato intervallo:
allow list: if request.query.limit <= 10;
La serie di regole seguente mostra come scrivere regole di sicurezza che valutano
i vincoli posti alle query. Questo esempio espande la versione precedente di stories
set di regole con le seguenti modifiche:
- Il set di regole separa la regola di lettura in regole per
get
elist
. - La regola
get
limita il recupero di singoli documenti ai documenti pubblici documenti creati dall'utente. - La regola
list
applica le stesse limitazioni diget
tranne che per le query. it controlla anche il limite di query, quindi nega qualsiasi query senza un limite o con un un limite superiore a 10. - Il set di regole definisce una funzione
authorOrPublished()
per evitare codice duplicati.
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 e regole di sicurezza del gruppo di raccolte
Per impostazione predefinita, le query hanno come ambito una singola raccolta e recuperano i risultati solo da quella raccolta. Con query sul gruppo di raccolte, puoi recupera 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.
Proteggi e esegui query sui documenti in base ai gruppi di raccolte
Nelle regole di sicurezza, devi consentire esplicitamente le query sul gruppo di raccolte scrivendo una regola per il gruppo di raccolte:
- Assicurati che
rules_version = '2';
sia la prima riga del set di regole. Raccolta le query del gruppo richiedono nuovo comportamento della sicurezza con caratteri jolly ricorsivi{name=**}
la versione 2 delle regole. - Scrivi una regola per il tuo gruppo di raccolte utilizzando
match /{path=**}/[COLLECTION_ID]/{doc}
.
Ad esempio, considera un forum organizzato in forum
documenti contenenti
posts
raccolte secondarie:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
In questa applicazione i post possono essere modificati dai proprietari e leggibili 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()
E se volessi mostrare all'utente corrente i suoi post in tutti i forum?
Puoi utilizzare una query sul gruppo di raccolta per recuperare
risultati da tutte le posts
raccolte:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
Nelle regole di sicurezza, devi consentire questa query
scrivere una regola di lettura o di elenco per il gruppo di raccolte posts
:
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;
}
}
}
Tuttavia, tieni presente che queste regole verranno applicate a tutte le raccolte con ID posts
,
a prescindere dalla gerarchia. Ad esempio, queste regole si applicano a tutti i
posts
raccolte:
/posts/{postid}
/forums/{forumid}/posts/{postid}
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Proteggere le query sui gruppi di raccolte in base a un campo
Come per le query a raccolta singola, anche le query dei gruppo di raccolte devono soddisfare i
i vincoli impostati dalle tue regole di sicurezza. Ad esempio, possiamo aggiungere published
in ogni post del forum, come abbiamo fatto nell'esempio precedente (stories
):
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
Possiamo quindi scrivere le regole per il gruppo di raccolte posts
in base al
published
e il 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 da un autore in 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 in tutti forum:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Proteggi ed esegui query sui documenti in base al gruppo di raccolte e al percorso del documento
In alcuni casi, potresti voler limitare le query gruppo di raccolte in base nel percorso del documento. Per creare queste restrizioni, puoi utilizzare le stesse tecniche per la protezione e l'esecuzione di query sui documenti sulla base di un campo.
Prendiamo in considerazione un'applicazione che tiene traccia delle transazioni di ciascun 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",
}
Osserva il campo user
. Anche se sappiamo quale utente possiede un documento transaction
dal percorso del documento, duplichiamo queste informazioni in ogni
documento transaction
perché ci consente di fare due cose:
Scrivi query sui gruppi di raccolte limitate ai documenti che includono un elemento
/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)
Applica questa limitazione per tutte le query sulla raccolta
transactions
in modo che un utente non possa recuperare i documentitransaction
di un altro utente.
Applichiamo questa limitazione nelle nostre regole di sicurezza e includiamo la convalida dei dati per il campo user
:
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 su ruoli, consulta Protezione dei dati Accesso per utenti e gruppi.
- Leggi la documentazione di riferimento alle regole di sicurezza.