Estoy aprendiendo Firestore y he creado una aplicación angular. Estoy usando la autenticación de Firebase y tengo problemas para descifrar las reglas que se deben usar para permitir que un usuario acceda a sus datos. Entonces, por ejemplo, una colección de productos en la que cada producto tiene un ID de usuario que en realidad es su dirección de correo electrónico.
La regla actual que tengo es la siguiente y no funciona (he intentado todo lo que puedo deducir según documentos, stackoverflow, etc.):
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userEmail} { allow read, write: if request.auth != null; } match /products/{userId}{ allow read, write: if request.auth.uid.userEmail == userId } } }Lo único que he hecho que funciona (es decir, recupero todos los productos) es si hago una coincidencia/{document=**) que lo abre a cualquiera que NO es lo que quiero. :)
¿Algunas ideas?
Editar: en caso de que alguien se pregunte sobre el código angular. Nuevamente, si configuro la regla para permitir cualquier cosa, SÍ obtendré datos de vuelta. Si lo restrinjo, hasta ahora no obtengo nada. Entonces, sé que el código funciona (getAll), por lo que debe ser que las reglas no son correctas.
Editar: actualicé el código para escribir el correo electrónico de los usuarios en la consola justo antes de solicitar todos los datos de productos de la tienda. Emitió con éxito el correo electrónico del usuario.
import { Injectable } from '@angular/core'; import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore'; import { AngularFireAuth } from '@angular/fire/auth'; import { Product } from '../models/product.model'; @Injectable({ providedIn: 'root' }) export class ProductsService { private dbPath = '/products'; productsRef: AngularFirestoreCollection<Product>; constructor(public afAuth: AngularFireAuth, private db: AngularFirestore) { this.productsRef = db.collection(this.dbPath); } getAll(): AngularFirestoreCollection<Product>{ this.afAuth.authState.subscribe(user => { console.log('Dashboard: user', user); if (user) { let emailLower = user.email.toLowerCase(); console.log("Email: " + emailLower); } }); return this.productsRef; } create(product: Product): any { return this.productsRef.add(product); } update(id: string, data: any): Promise<void>{ return this.productsRef.doc(id).update(data); } delete(id: string): Promise<void> { return this.productsRef.doc(id).delete(); } }Creo que hay algún problema con las reglas de seguridad construidas. Puedeconsultar las reglas de seguridad de Firestore para obtener más información sobre cómo escribir reglas y, para probar sus reglas, puede consultar la documentación donde se menciona:
Cloud Firestore proporciona un simulador de reglas que puede usar para probar su conjunto de reglas. Puede acceder al simulador desde la pestaña Reglas en la sección Cloud Firestore de Firebase console. El simulador de reglas le permite simular lecturas, escrituras y eliminaciones autenticadas y no autenticadas.
a) En la captura de pantalla de la colección de productos de la base de datos de Firestore, el ID del documento parece ser una secuencia alfanumérica generada automáticamente. Por lo tanto, las siguientes reglas de coincidencia coincidirán con el ID del documento (generado automáticamente) en las variables {userEmail} y {userId} en lugar del correo electrónico o el ID del usuario, como sugiere el nombre de la variable.
match /users/{userEmail} match /products/{userId}Por supuesto, puede crear ID de documento para tener direcciones de correo electrónico en lugar de secuencias generadas automáticamente, en cuyo caso las condiciones de coincidencia anteriores podrían funcionar como se esperaba.
b) El uso de request.auth.uid.userEmail es incorrecto. La forma correcta de referirse al correo electrónico desde el estado de autenticación de solicitud de un usuario es "request.auth.token.email" . Puede leer acerca de las request.auth & resource variable references en los documentos públicos de Firestore: documentación 1 y documentación 2 para usar la sintaxis correcta.
c) A continuación se presentan algunas correcciones realizadas a las reglas de seguridad. Esto debería funcionar.
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userDocId} { allow read, write: if request.auth != null; } match /products/{productDocId}{ allow read, write: if request.auth.token.email == resource.data.userId } } }