Firestore es una base de datos no relacional muy flexible de la familia de Firebase y gracias las reglas de seguridad podemos administrar el acceso y las capacidades de nuestros usuarios para que puedan o no realizar ciertas acciones en nuestra base de datos.
Estas reglas son muy sencillas de configurar pero también son muy poderosas. Firebase se encarga del trabajo pesado. Solo debemos conocer muy bien nuestra aplicación y comprobar que las reglas realmente pueden proteger la integridad de nuestras aplicaciones.
Tenemos diferentes tipos de objetos para construir nuestras aplicaciones con Firestore: colecciones y documentos sencillos o complejos.
Documentos: Los documentos (sencillos) son diccionarios de datos que podemos guardar en formato de llave => valor
. Además, podemos crear documentos anidados, algo así como subdocumentos. Si estás acostumbrado al mundo de JavaScript puedes entender estos documentos complejos como objetos; cada objeto puede tener más objetos y así sucesivamente.
Sin embargo, los documentos complejos también pueden volver nuestras aplicaciones --aún-- más complejas. Firebase nos permite hacer consultas por documentos, esto significa que si tenemos una cascada de subdocumentos nuestras consultas van a tomar cada vez más tiempo y van a ser más difíciles de mantener.
Colecciones: Las colecciones son conjuntos de documentos. Podemos tener una colección de usuarios, una colección para las pizzas, otra para tipos de animales, etc. Más que todo sirven para organizar nuestra información. La recomendación es no tener ni más ni menos colecciones de las que realmente necesitamos.
Al tener muchas colecciones, por no guardar todo en un mismo sitio, vamos a necesitar referencias que nos indiquen dónde conseguir los datos que hacen falta. Esto significa que debemos hacer demasiadas consultas para conseguir la información suficiente. Vamos a gastar mucho tiempo entre consulta y consulta.
De la misma forma, si usamos muy pocas colecciones (abusando de los documentos anidados), cada consulta va a tomar más tiempo de lo que podemos esperar y vamos a recibir mucha información que realmente no vamos a utilizar.
En resumen: Usa Firestore con responsabilidad.
Las reglas de seguridad nos ayudan a determinar quién puede o tiene permisos para hacer algo: leer, escribir, crear, actualizar, borrar, entre otras. Podemos restringir el acceso a toda una colección o a documentos específicos dependiendo de nuestra lógica de negocios.
Debemos entender muy bien cómo funcionan nuestras aplicaciones y personalizar estas reglas con diferentes combinaciones hasta “asegurarnos” que realmente funcionan como debe ser.
Cómo crear una regla de seguridad:
Service
: Todas las reglas comienzan especificando el servicio sobre el cual deben actuar. En este caso, debemos indicarle a Firebase que queremos usar Firestore con la siguiente expresión:servicecloud.firestore {
...
}
Match
: Indicamos las colecciones y documentos sobre los cuales deben a aplicar nuestras reglas de seguridad. Podemos tener múltiples expresiones match
. Incluso, unas dentro de otras:service cloud.firestore {
match /databases/{database}/documents {
match /<some_path>/ {
...
}
match /<some_other_path>/ {
...
}
}
}
Allow
: Definimos los permisos para la “ruta” de colecciones y documentos que definimos anteriormente. Podemos usar las expresiones read
, write
, create
, update
o delete
seguido de dos puntos (:
), la expresión if
y la condición que debemos cumplir para otorgar o denegar el permiso:service cloud.firestore {
match /databases/{database}/documents {
match /test/ {
allow read, write: iftrue;
}
match /<some_other_path>/ {
allow create, delete: if false;
}
}
}
Siempre debemos escribir un punto y coma ;
al final.
Afortunadamente, no solo podemos usar las expresiones true y false para limitar el acceso a ciertas partes de nuestra base de datos; también podemos acceder a la información de los usuarios que realizan las peticiones, los datos guardados en los documentos que queremos actualizar y los nuevos campos que los usuarios envían para editar los documentos.
A continuación, vamos a ver algunos ejemplos de reglas de seguridad para casos muy específicos. Pueden ser de utilidad para ti, tu equipo o tu aplicación.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: iffalse;
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: iftrue;
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.id != null;
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /users {
allow read, write: if request.resource.data.username == resource.data.username;
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
// Podemos modificar la data del usuario si el userId del modificador// es el mismo del usuario a modificar...
allow read, update, delete: if request.auth.uid == userID;
// Permite crear usuarios si estamos autenticados porque, si el usuario// no existe, no podemos verificar su ID...
allow create: if request.auth.uid != null;
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow update: if request.resource.data.population > 0
&& request.resource.data.name == resource.data.name;
}
}
}
is_public
y can_edit
de cada documento determinen si la información puede ser leída o actualizada y por quién:service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow read: resource.data.is_public == true;
allow read: resource.data.can_edit == "any";
}
}
}
Firebase nos ofrece un simulador: una herramienta para comprobar que nuestras reglas de seguridad permiten o restringen el acceso a nuestros datos de manera correcta. No dudes en probar estas y todas las combinaciones de reglas de seguridad que se te ocurran.
Sin embargo, recuerda que no podemos confiar al 100% en este simulador. La mejor forma de comprobar que nuestras reglas realmente funcionan como esperamos es programando el código de nuestras aplicaciones y probar sin miedo 🔥.
Las reglas de seguridad en Firestore son una de mis características favoritas entre todos los servicios de Firebase. Vale totalmente la pena invertir un buen tiempo en crearlas y organizarlas correctamente.
Puedes aprender mucho más sobre los servicios de Firestore y Firebase Authentication con el Curso de Firestore para Android. Vamos a construir una aplicación móvil para consumir cripto-monedas en tiempo real. Nuestro profesor será Santiago Carrillo, @sancarbar, Google Developer Expert en Android con más de 7 años de experiencia creando aplicaciones.
Te invito a estudiar las mejores prácticas de todos estos servicios. Ya sabes, un gran poder conlleva una gran responsabilidad.
#NuncaParesDeAprender 🤓💚
alguna regla para no permitir datos duplicados?
Me interesa, descubriste alguna?
Dentro de las reglas de seguridad puedes crear funciones y metodos get, sin embargo creo que hay un máximo de llamadas
Excelente articulo, muy util.
Buen dia, estoy con reglas de firestore, para la creación me funciona pero para el borrado no, aunque según yo debería ser lo mismo, lo que intento hacer es que solo permita crear y borrar documentos si el documento contiene en un campo el ID del usuario autenticado o bien si es un usuario que sea Admin, no entiendo por que para crear si me funciona pero para borrar me marca error 😦 ¿que cambia para el borrado?
Aquí el ejemplo, repito el write funciona, el delete no 😦
match /pagos/{year}/pagos/{id} {
allow write: if request.auth.uid == request.resource.data.alumnoId ||
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin;
allow delete: if request.auth.uid == request.resource.data.alumnoId ||
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin;
}
Puedes utilizar
resource.data.alumnoId
en vez deldel
request.resource.data.alumnoId
para hacer el delete.