Esta página se basa en los conceptos de Estructuración de reglas de seguridad y Condiciones de escritura para reglas de seguridad para explicar cómo interactúan las reglas de seguridad de Cloud Firestore con las consultas. Da un vistazo más de cerca a cómo las reglas de seguridad afectan las consultas que puede escribir y describe cómo asegurarse de que sus consultas usen 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 potencial en lugar de los valores de campo reales para todos sus documentos. Si una consulta podría devolver documentos que el cliente no tiene permiso para leer, la solicitud completa falla.
Consultas y reglas de seguridad
Como demuestran los ejemplos a continuación, debe escribir sus consultas para que se ajusten a las restricciones de sus reglas de seguridad.
Asegure y consulte 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 de story
:
/historias/{id de la historia}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
Además de los campos de title
y content
, cada documento almacena el author
y los campos published
para usarlos para el control de acceso. Estos ejemplos asumen que la aplicación usa Firebase Authentication para establecer el campo de 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;
}
}
}
Suponga que su aplicación incluye una página que le muestra al usuario una lista de documentos de story
que ellos mismos crearon. Es de esperar que pueda usar 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 realmente el autor de cada documento de la story
. El motivo de este comportamiento es que cuando Cloud Firestore aplica sus reglas de seguridad, evalúa la consulta según su conjunto de resultados potencial , no según las propiedades reales de los documentos en su base de datos. Si una consulta podría incluir potencialmente documentos que violan sus reglas de seguridad, la consulta fallará.
Por el contrario, la siguiente consulta tiene éxito porque incluye la misma restricción en el campo de 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()
Asegure y consulte documentos basados en un campo
Para demostrar aún más la interacción entre las consultas y las reglas, las reglas de seguridad a continuación amplían el acceso de lectura para la colección de stories
para permitir que cualquier usuario lea documentos de story
donde el campo published
se establece 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
es true
para cualquier resultado. Por lo tanto, esta consulta cumple con las reglas de seguridad y puede leer datos.
in
y array-contains-any
consulta
Al evaluar una cláusula de consulta 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 con las restricciones de la regla 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
// This query will fail
db.collection("mydocuments").where("x", "in", [1, 3, 6, 42, 99]).get()
Válido : la consulta garantiza que x > 5
para todos los documentos potenciales
db.collection("mydocuments").where("x", "in", [6, 42, 99, 105, 200]).get()
Evaluación de restricciones en consultas
Sus reglas de seguridad también pueden aceptar o denegar consultas en función de sus restricciones. La variable request.query
contiene las propiedades 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 cierto rango:
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 de las 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 creados por el usuario. - La regla de
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 superior 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 colecciones y reglas de seguridad
De forma predeterminada, las consultas se limitan a una sola colección y recuperan resultados solo 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. En esta sección, se describe cómo proteger las consultas de su grupo de recopilación mediante reglas de seguridad.
Asegure y consulte documentos basados en grupos de colección
En sus reglas de seguridad, debe permitir explícitamente consultas de grupos de recopilación escribiendo una regla para el grupo de recopilación:
- Asegúrese de que
rules_version = '2';
es la primera línea de su conjunto de reglas. Las consultas de grupos de colecciones requieren el nuevo comportamiento de 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 de forum
que contengan subcolecciones de posts
:
/foros/{forumid}/mensajes/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
En esta aplicación, hacemos publicaciones 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 mostrar al usuario actual sus publicaciones en todos los foros? Puede usar una consulta de grupo de colección para recuperar resultados de todas las colecciones de 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 recopilación de 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;
}
}
}
Tenga en cuenta, sin embargo, que estas reglas se aplicarán a todas las colecciones con posts
de identificación, independientemente de la jerarquía. Por ejemplo, estas reglas se aplican a todas las siguientes colecciones de posts
:
-
/posts/{postid}
-
/forums/{forumid}/posts/{postid}
-
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Consultas seguras de grupos de recopilación basadas en un campo
Al igual que las consultas de colección única, las consultas de grupo de colección también deben cumplir las restricciones establecidas por las reglas de seguridad. Por ejemplo, podemos agregar un campo published
a cada publicación del foro como hicimos en el ejemplo de stories
anterior:
/foros/{forumid}/mensajes/{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 de posts
según el estado 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()
Asegure y consulte documentos según el grupo de colección y la ruta del documento
En algunos casos, es posible que desee restringir las consultas de grupos de colecciones en función de la ruta del documento. Para crear estas restricciones, puede usar las mismas técnicas para asegurar y consultar documentos basados en un campo.
Considere una aplicación que realiza un seguimiento de las transacciones de cada usuario entre varios intercambios de acciones y criptomonedas:
/usuarios/{idusuario}/intercambio/{idintercambio}/transacciones/{transacción}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
Observe el campo de user
. Aunque sabemos qué usuario posee un documento de transaction
por la ruta del documento, duplicamos esta información en cada documento de transaction
porque nos permite hacer dos cosas:
Escriba consultas de grupos de colecciones 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 de
transactions
para que un usuario no pueda recuperar los documentos detransaction
de otro usuario.
Aplicamos esta restricción en nuestras reglas de seguridad e incluimos la validación de datos para el campo de 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 funciones, consulte Protección del acceso a datos para usuarios y grupos .
- Lea la referencia de las reglas de seguridad .