获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

Pruebe sus reglas de seguridad de Cloud Firestore

A medida que crea su aplicación, es posible que desee bloquear el acceso a su base de datos de Cloud Firestore. Sin embargo, antes del lanzamiento, necesitará reglas de seguridad de Cloud Firestore más matizadas. Con el emulador de Cloud Firestore, además de crear prototipos y probar las funciones y el comportamiento generales de su aplicación, puede escribir pruebas unitarias que verifiquen el comportamiento de sus reglas de seguridad de Cloud Firestore.

Inicio rápido

Para algunos casos de prueba básicos con reglas simples, pruebe la muestra de inicio rápido .

Comprender las reglas de seguridad de Cloud Firestore

Implemente las reglas de seguridad de Firebase Authentication y Cloud Firestore para la autenticación, la autorización y la validación de datos sin servidor cuando use las bibliotecas de clientes móviles y web.

Las reglas de seguridad de Cloud Firestore incluyen dos partes:

  1. Una declaración de match que identifica documentos en su base de datos.
  2. Una expresión allow que controla el acceso a esos documentos.

Firebase Authentication verifica las credenciales de los usuarios y proporciona la base para los sistemas de acceso basados ​​en roles y usuarios.

Cada solicitud de base de datos de una biblioteca de cliente web/móvil de Cloud Firestore se evalúa según sus reglas de seguridad antes de leer o escribir cualquier dato. Si las reglas niegan el acceso a cualquiera de las rutas de documentos especificadas, la solicitud completa falla.

Obtenga más información sobre las reglas de seguridad de Cloud Firestore en Introducción a las reglas de seguridad de Cloud Firestore .

Instala el emulador

Para instalar el emulador de Cloud Firestore, use Firebase CLI y ejecute el siguiente comando:

firebase setup:emulators:firestore

Ejecutar el emulador

Comience inicializando un proyecto de Firebase en su directorio de trabajo. Este es un primer paso común cuando se usa Firebase CLI .

firebase init

Inicie el emulador con el siguiente comando. El emulador se ejecutará hasta que elimines el proceso:

firebase emulators:start --only firestore

En muchos casos, desea iniciar el emulador, ejecutar un conjunto de pruebas y luego apagar el emulador después de ejecutar las pruebas. Puedes hacer esto fácilmente usando el comando emulators:exec :

firebase emulators:exec --only firestore "./my-test-script.sh"

Cuando se inicie, el emulador intentará ejecutarse en un puerto predeterminado (8080). Puedes cambiar el puerto del emulador modificando la sección "emulators" de tu archivo firebase.json :

{
  // ...
  "emulators": {
    "firestore": {
      "port": "YOUR_PORT"
    }
  }
}

Antes de ejecutar el emulador

Antes de comenzar a usar el emulador, tenga en cuenta lo siguiente:

  • El emulador cargará inicialmente las reglas especificadas en el campo firestore.rules de su archivo firebase.json . Espera el nombre de un archivo local que contiene sus reglas de seguridad de Cloud Firestore y aplica esas reglas a todos los proyectos. Si no proporciona la ruta del archivo local o no usa el método loadFirestoreRules como se describe a continuación, el emulador trata todos los proyectos como si tuvieran reglas abiertas.
  • Si bien la mayoría de los SDK de Firebase funcionan directamente con los emuladores, solo la @firebase/rules-unit-testing admite la auth en las reglas de seguridad, lo que facilita mucho las pruebas unitarias. Además, la biblioteca admite algunas características específicas del emulador, como borrar todos los datos, como se indica a continuación.
  • Los emuladores también aceptarán tokens de Firebase Auth de producción proporcionados a través de SDK de cliente y evaluarán las reglas en consecuencia, lo que permite conectar su aplicación directamente a los emuladores en la integración y las pruebas manuales.

Ejecutar pruebas de unidades locales

Ejecute pruebas de unidades locales con el SDK de JavaScript v9

Firebase distribuye una biblioteca de pruebas unitarias de reglas de seguridad con su SDK de JavaScript de la versión 9 y su SDK de la versión 8. Las API de la biblioteca son significativamente diferentes. Recomendamos la biblioteca de prueba v9, que está más optimizada y requiere menos configuración para conectarse a los emuladores y, por lo tanto, evitar el uso accidental de recursos de producción de forma segura. Para compatibilidad con versiones anteriores, continuamos poniendo a disposición la biblioteca de prueba v8 .

Use el @firebase/rules-unit-testing para interactuar con el emulador que se ejecuta localmente. Si obtiene tiempos de espera o errores ECONNREFUSED , vuelva a verificar que el emulador se esté ejecutando.

Recomendamos enfáticamente usar una versión reciente de Node.js para que pueda usar la notación async/await . Casi todo el comportamiento que podría querer probar involucra funciones asincrónicas, y el módulo de prueba está diseñado para funcionar con código basado en Promise.

La biblioteca de pruebas unitarias de reglas v9 siempre está al tanto de los emuladores y nunca toca sus recursos de producción.

La biblioteca se importa mediante sentencias de importación modular v9. Por ejemplo:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment,
  RulesTestEnvironment,
} from "@firebase/rules-unit-testing"

// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.

Una vez importados, implementar pruebas unitarias implica:

  • Crear y configurar un RulesTestEnvironment con una llamada a initializeTestEnvironment .
  • Configuración de datos de prueba sin activar Reglas, usando un método conveniente que le permite omitirlos temporalmente, RulesTestEnvironment.withSecurityRulesDisabled .
  • Configurar el conjunto de pruebas y los ganchos antes/después de cada prueba con llamadas para limpiar los datos y el entorno de prueba, como RulesTestEnvironment.cleanup() o RulesTestEnvironment.clearFirestore() .
  • Implementar casos de prueba que imiten estados de autenticación usando RulesTestEnvironment.authenticatedContext y RulesTestEnvironment.unauthenticatedContext .

Métodos comunes y funciones de utilidad

Consulte también los métodos de prueba específicos del emulador en el SDK v9 .

initializeTestEnvironment() => RulesTestEnvironment

Esta función inicializa un entorno de prueba para las pruebas unitarias de reglas. Primero llame a esta función para la configuración de prueba. La ejecución exitosa requiere que los emuladores se estén ejecutando.

La función acepta un objeto opcional que define un TestEnvironmentConfig , que puede consistir en un ID de proyecto y ajustes de configuración del emulador.

let testEnv = await initializeTestEnvironment({
  projectId: "demo-project-1234",
  firestore: {
    rules: fs.readFileSync("firestore.rules", "utf8"),
  },
});

RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext

Este método crea un RulesTestContext , que se comporta como un usuario de autenticación autenticado. Las solicitudes creadas a través del contexto devuelto tendrán adjunto un token de autenticación simulado. Opcionalmente, pase un objeto que defina reclamos personalizados o anulaciones para las cargas útiles del token de autenticación.

Use el objeto de contexto de prueba devuelto en sus pruebas para acceder a cualquier instancia de emulador configurada, incluidas las configuradas con initializeTestEnvironment .

// Assuming a Firestore app and the Firestore emulator for this example
import { setDoc } from "firebase/firestore";

const alice = testEnv.authenticatedContext("alice", { … });
// Use the Firestore instance associated with this context
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

Este método crea un RulesTestContext , que se comporta como un cliente que no ha iniciado sesión a través de la autenticación. Las solicitudes creadas a través del contexto devuelto no tendrán tokens de autenticación de Firebase adjuntos.

Use el objeto de contexto de prueba devuelto en sus pruebas para acceder a cualquier instancia de emulador configurada, incluidas las configuradas con initializeTestEnvironment .

// Assuming a Cloud Storage app and the Storage emulator for this example
import { getStorage, ref, deleteObject } from "firebase/storage";

const alice = testEnv.unauthenticatedContext();

// Use the Cloud Storage instance associated with this context
const desertRef = ref(alice.storage(), 'images/desert.jpg');
await assertSucceeds(deleteObject(desertRef));

RulesTestEnvironment.withSecurityRulesDisabled()

Ejecute una función de configuración de prueba con un contexto que se comporte como si las Reglas de seguridad estuvieran deshabilitadas.

Este método toma una función de devolución de llamada, que toma el contexto de omisión de reglas de seguridad y devuelve una promesa. El contexto se destruirá una vez que la promesa se resuelva/rechace.

RulesTestEnvironment.cleanup()

Este método destruye todos los RulesTestContexts creados en el entorno de prueba y limpia los recursos subyacentes, lo que permite una salida limpia.

Este método no cambia el estado de los emuladores de ninguna manera. Para restablecer los datos entre pruebas, use el método de borrado de datos específico del emulador de la aplicación.

assertSucceeds(pr: Promise<any>)) => Promise<any>

Esta es una función de utilidad de caso de prueba.

La función afirma que la Promesa suministrada que envuelve una operación de emulador se resolverá sin violaciones de las reglas de seguridad.

await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

assertFails(pr: Promise<any>)) => Promise<any>

Esta es una función de utilidad de caso de prueba.

La función afirma que la Promesa suministrada que envuelve una operación de emulador será rechazada con una violación de las Reglas de seguridad.

await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });

Métodos específicos del emulador

Consulte también los métodos de prueba comunes y las funciones de utilidad en el SDK v9 .

RulesTestEnvironment.clearFirestore() => Promise<void>

Este método borra los datos en la base de datos de Firestore que pertenecen al projectId configurado para el emulador de Firestore.

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

Este método obtiene una instancia de Firestore para este contexto de prueba. La instancia de Firebase JS Client SDK devuelta se puede usar con las API de SDK de cliente (v9 modular o v9 compat).

Visualizar evaluaciones de reglas

El emulador de Cloud Firestore le permite visualizar las solicitudes de los clientes en la interfaz de usuario de Emulator Suite, incluido el seguimiento de evaluación para las reglas de seguridad de Firebase.

Abra la pestaña Firestore > Solicitudes para ver la secuencia de evaluación detallada de cada solicitud.

Firestore Emulator Requests Monitor que muestra las evaluaciones de las reglas de seguridad

Generar informes de prueba

Después de ejecutar un conjunto de pruebas, puede acceder a los informes de cobertura de prueba que muestran cómo se evaluó cada una de sus reglas de seguridad.

Para obtener los informes, consulta un extremo expuesto en el emulador mientras se está ejecutando. Para obtener una versión compatible con el navegador, use la siguiente URL:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html

Esto divide sus reglas en expresiones y subexpresiones sobre las que puede pasar el mouse para obtener más información, incluida la cantidad de evaluaciones y valores devueltos. Para la versión JSON sin procesar de estos datos, incluya la siguiente URL en su consulta:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage

Diferencias entre el emulador y la producción.

  1. No tiene que crear explícitamente un proyecto de Cloud Firestore. El emulador crea automáticamente cualquier instancia a la que se acceda.
  2. El emulador de Cloud Firestore no funciona con el flujo normal de autenticación de Firebase. En cambio, en el SDK de prueba de Firebase, proporcionamos el método initializeTestApp() en la biblioteca rules-unit-testing , que toma un campo de auth . El identificador de Firebase creado con este método se comportará como si se hubiera autenticado correctamente como cualquier entidad que proporcione. Si pasa null , se comportará como un usuario no autenticado (las reglas auth != null fallarán, por ejemplo).

Solucionar problemas conocidos

A medida que usa el emulador de Cloud Firestore, es posible que se encuentre con los siguientes problemas conocidos. Siga las instrucciones a continuación para solucionar cualquier comportamiento irregular que esté experimentando. Estas notas están escritas teniendo en cuenta la biblioteca de pruebas unitarias de reglas de seguridad, pero los enfoques generales se aplican a cualquier SDK de Firebase.

El comportamiento de la prueba es inconsistente

Si sus pruebas aprueban y fallan ocasionalmente, incluso sin ningún cambio en las pruebas en sí, es posible que deba verificar que estén secuenciadas correctamente. La mayoría de las interacciones con el emulador son asincrónicas, así que verifique que todo el código asincrónico esté correctamente secuenciado. Puede corregir la secuencia encadenando promesas o usando la notación de await generosamente.

En particular, revise las siguientes operaciones asincrónicas:

  • Establecer reglas de seguridad, con, por ejemplo, initializeTestEnvironment .
  • Lectura y escritura de datos, con, por ejemplo, db.collection("users").doc("alice").get() .
  • assertSucceeds operativas, incluidas las afirmaciones exitosas y assertFails .

Las pruebas solo pasan la primera vez que carga el emulador

El emulador tiene estado. Almacena todos los datos escritos en él en la memoria, por lo que cualquier dato se pierde cada vez que se apaga el emulador. Si está ejecutando varias pruebas con el mismo ID de proyecto, cada prueba puede producir datos que podrían influir en las pruebas posteriores. Puede utilizar cualquiera de los siguientes métodos para omitir este comportamiento:

  • Use ID de proyecto únicos para cada prueba. Tenga en cuenta que si elige hacer esto, deberá llamar a initializeTestEnvironment como parte de cada prueba; las reglas solo se cargan automáticamente para el ID de proyecto predeterminado.
  • Reestructura tus pruebas para que no interactúen con datos escritos previamente (por ejemplo, usa una colección diferente para cada prueba).
  • Borra todos los datos escritos durante una prueba.

La configuración de la prueba es muy complicada.

Al configurar su prueba, es posible que desee modificar los datos de una manera que sus Reglas de seguridad de Cloud Firestore no permitan. Si sus reglas hacen que la configuración de la prueba sea compleja, intente usar RulesTestEnvironment.withSecurityRulesDisabled en sus pasos de configuración, para que las lecturas y escrituras no generen errores PERMISSION_DENIED .

Después de eso, su prueba puede realizar operaciones como un usuario autenticado o no autenticado usando RulesTestEnvironment.authenticatedContext y unauthenticatedContext respectivamente. Esto le permite validar que sus Reglas de seguridad de Cloud Firestore permiten/deniegan diferentes casos correctamente.