Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Consultar datos de forma segura

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

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 y list .
  • 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 que get 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:

  1. 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.
  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 de transaction 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