Esta página se basa en los conceptos de Estructuración de reglas de seguridad y Escritura de condiciones para reglas de seguridad para explicar cómo las reglas de seguridad de Cloud Firestore interactúan con las consultas. Examina más de cerca cómo las reglas de seguridad afectan las consultas que puede escribir y describe cómo garantizar que sus consultas utilicen las mismas restricciones que sus reglas de seguridad. Esta página también describe cómo escribir reglas de seguridad para permitir o denegar consultas basadas en propiedades de consulta como limit
y orderBy
.
Las reglas no son filtros
Al escribir consultas para recuperar documentos, tenga en cuenta que las reglas de seguridad no son filtros: las consultas son todo o nada. Para ahorrarle tiempo y recursos, Cloud Firestore evalúa una consulta con su conjunto de resultados potenciales en lugar de con los valores de campo reales de todos sus documentos. Si una consulta podría devolver documentos que el cliente no tiene permiso para leer, toda la solicitud falla.
Consultas y reglas de seguridad.
Como lo demuestran los ejemplos siguientes, debe escribir sus consultas para que se ajusten a las limitaciones de sus reglas de seguridad.
Proteger y consultar documentos basados en auth.uid
El siguiente ejemplo demuestra cómo escribir una consulta para recuperar documentos protegidos por una regla de seguridad. Considere una base de datos que contiene una colección de documentos story
:
/historias/{id de historia}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
Además de los campos title
y content
, cada documento almacena el author
y los campos published
para utilizarlos en el control de acceso. Estos ejemplos suponen que la aplicación usa Firebase Authentication para establecer el campo author
en el UID del usuario que creó el documento. Firebase Authentication también completa la variable request.auth
en las reglas de seguridad.
La siguiente regla de seguridad utiliza las variables request.auth
y resource.data
para restringir el acceso de lectura y escritura de cada story
a su autor:
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;
}
}
}
Supongamos que su aplicación incluye una página que muestra al usuario una lista de documentos story
de su autoría. Es de esperar que pueda utilizar la siguiente consulta para completar esta página. Sin embargo, esta consulta fallará porque no incluye las mismas restricciones que sus reglas de seguridad:
No válido : las restricciones de consulta no coinciden con las restricciones de las reglas de seguridad
// This query will fail
db.collection("stories").get()
La consulta falla incluso si el usuario actual es en realidad el autor de cada documento story
. El motivo de este comportamiento es que cuando Cloud Firestore aplica sus reglas de seguridad, evalúa la consulta con su conjunto de resultados potenciales , no con las propiedades reales de los documentos en su base de datos. Si una consulta podría incluir documentos que violen sus reglas de seguridad, la consulta fallará.
Por el contrario, la siguiente consulta tiene éxito porque incluye la misma restricción en el campo author
que las reglas de seguridad:
Válido : las restricciones de consulta coinciden con las restricciones de las reglas de seguridad.
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Proteger y consultar documentos basados en un campo.
Para demostrar aún más la interacción entre consultas y reglas, las reglas de seguridad siguientes amplían el acceso de lectura a la colección stories
para permitir que cualquier usuario lea documentos story
donde el campo published
esté establecido en 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 consulta de páginas publicadas debe incluir las mismas restricciones que las reglas de seguridad:
db.collection("stories").where("published", "==", true).get()
La restricción de consulta .where("published", "==", true)
garantiza que resource.data.published
sea true
para cualquier resultado. Por lo tanto, esta consulta satisface las reglas de seguridad y puede leer datos.
OR
consultas
Al evaluar una consulta OR
lógica ( or
, in
, o array-contains-any
) con un conjunto de reglas, Cloud Firestore evalúa cada valor de comparación por separado. Cada valor de comparación debe cumplir las restricciones de las reglas de seguridad. Por ejemplo, para la siguiente regla:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
No válido : la consulta no garantiza que x > 5
para todos los documentos potenciales
// 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])
)
Válido : la consulta garantiza que x > 5
para todos los documentos potenciales
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
Evaluación de restricciones en consultas
Sus reglas de seguridad también pueden aceptar o rechazar consultas según sus restricciones. La variable request.query
contiene las limit
, offset
y orderBy
de una consulta. Por ejemplo, sus reglas de seguridad pueden rechazar cualquier consulta que no limite la cantidad máxima de documentos recuperados a un rango determinado:
allow list: if request.query.limit <= 10;
El siguiente conjunto de reglas demuestra cómo escribir reglas de seguridad que evalúen las restricciones impuestas a las consultas. Este ejemplo amplía el conjunto de reglas stories
anteriores con los siguientes cambios:
- El conjunto de reglas separa la regla de lectura en reglas para
get
ylist
. - La regla
get
restringe la recuperación de documentos individuales a documentos públicos o documentos escritos por el usuario. - La regla
list
aplica las mismas restricciones queget
pero para consultas. También verifica el límite de consultas, luego rechaza cualquier consulta sin límite o con un límite mayor a 10. - El conjunto de reglas define una función
authorOrPublished()
para evitar la duplicación de código.
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;
}
}
}
Consultas de grupos de recopilación y reglas de seguridad.
De forma predeterminada, las consultas tienen como ámbito una única colección y recuperan resultados únicamente de esa colección. Con las consultas de grupos de colecciones , puede recuperar resultados de un grupo de colecciones que consta de todas las colecciones con el mismo ID. Esta sección describe cómo proteger las consultas de su grupo de recopilación mediante reglas de seguridad.
Proteger y consultar documentos basados en grupos de colección.
En sus reglas de seguridad, debe permitir explícitamente consultas del grupo de recopilación escribiendo una regla para el grupo de recopilación:
- Asegúrate de
rules_version = '2';
es la primera línea de su conjunto de reglas. Las consultas de grupos de colecciones requieren el nuevo comportamiento del comodín recursivo{name=**}
de las reglas de seguridad versión 2. - Escriba una regla para su grupo de colección usando
match /{path=**}/ [COLLECTION_ID] /{doc}
.
Por ejemplo, considere un foro organizado en documentos forum
que contienen subcolecciones posts
:
/foros/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
En esta aplicación, hacemos que las publicaciones sean editables por sus propietarios y legibles por usuarios autenticados:
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;
}
}
}
Cualquier usuario autenticado puede recuperar las publicaciones de cualquier foro:
db.collection("forums/technology/posts").get()
Pero, ¿qué sucede si desea mostrarle al usuario actual sus publicaciones en todos los foros? Puede utilizar una consulta de grupo de colecciones para recuperar resultados de todas las colecciones posts
:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
En sus reglas de seguridad, debe permitir esta consulta escribiendo una regla de lectura o lista para el grupo de colección 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;
}
}
}
Sin embargo, tenga en cuenta que estas reglas se aplicarán a todas las colecciones con posts
de ID, independientemente de la jerarquía. Por ejemplo, estas reglas se aplican a todas las siguientes colecciones posts
:
-
/posts/{postid}
-
/forums/{forumid}/posts/{postid}
-
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Consultas de grupos de recopilación segura basadas en un campo
Al igual que las consultas de una sola colección, las consultas de grupos de colecciones también deben cumplir las restricciones establecidas por sus reglas de seguridad. Por ejemplo, podemos agregar un campo published
a cada publicación del foro como lo hicimos en el ejemplo stories
anterior:
/foros/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
Luego podemos escribir reglas para el grupo de colección posts
según el estado de published
y el author
de la publicación:
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 estas reglas, los clientes Web, Apple y Android pueden realizar las siguientes consultas:
Cualquiera puede recuperar publicaciones publicadas en un foro:
db.collection("forums/technology/posts").where('published', '==', true).get()
Cualquiera puede recuperar las publicaciones de un autor en todos los foros:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
Los autores pueden recuperar todas sus publicaciones publicadas y no publicadas en todos los foros:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Proteger y consultar documentos según el grupo de recopilación y la ruta del documento
En algunos casos, es posible que desee restringir las consultas del grupo de recopilación según la ruta del documento. Para crear estas restricciones, puede utilizar las mismas técnicas para proteger y consultar documentos basados en un campo.
Considere una aplicación que realiza un seguimiento de las transacciones de cada usuario entre varias bolsas de valores y criptomonedas:
/usuarios/{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",
}
Observe el campo user
. Aunque sabemos qué usuario posee un documento transaction
a partir de la ruta del documento, duplicamos esta información en cada documento transaction
porque nos permite hacer dos cosas:
Escriba consultas de grupos de colección que estén restringidas a documentos que incluyan un
/users/{userid}
específico en la ruta del documento. Por ejemplo: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)
Aplique esta restricción para todas las consultas en el grupo de recopilación
transactions
para que un usuario no pueda recuperar los documentostransaction
de otro usuario.
Aplicamos esta restricción en nuestras reglas de seguridad e incluimos validación de datos para el 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
}
}
}
Próximos pasos
- Para obtener un ejemplo más detallado de control de acceso basado en roles, consulte Proteger el acceso a datos para usuarios y grupos .
- Lea la referencia de las reglas de seguridad .