Descubre Firebase para la Web

1. Descripción general

En este codelab, aprenderás algunos de los conceptos básicos de Firebase para crear aplicaciones web interactivas. Crearás una app de chat para confirmar asistencia al evento y un libro de visitas con varios productos de Firebase.

captura de pantalla de este paso

Qué aprenderás

  • Autentica usuarios con Firebase Authentication y FirebaseUI.
  • Sincronizar datos con Cloud Firestore
  • Escribe reglas de seguridad de Firebase para proteger una base de datos.

Requisitos

  • El navegador que prefieras, como Chrome
  • Acceso a stackblitz.com (no se necesita una cuenta ni acceso)
  • Una Cuenta de Google, como una cuenta de Gmail Te recomendamos la cuenta de correo electrónico que ya utilizas para tu cuenta de GitHub. Esto te permite usar funciones avanzadas en StackBlitz.
  • El código de muestra del codelab Consulta el siguiente paso para ver cómo obtener el código.

2. Obtén el código de partida

En este codelab, crearás una app con StackBlitz, un editor en línea que tiene varios flujos de trabajo de Firebase integrados. Stackblitz no requiere instalación de software ni una cuenta especial de StackBlitz.

StackBlitz te permite compartir proyectos con otras personas. Las demás personas que tienen la URL de tu proyecto de StackBlitz pueden ver tu código y bifurcar tu proyecto, pero no pueden editar tu proyecto de StackBlitz.

  1. Para obtener el código de inicio, ve a esta URL: https://stackblitz.com/edit/firebase-gtk-web-start
  2. En la parte superior de la página de StackBlitz, haz clic en Fork:

captura de pantalla de este paso

Ahora tienes una copia del código de inicio como tu propio proyecto de StackBlitz, que tiene un nombre único y una URL única. Todos tus archivos y cambios se guardan en este proyecto de StackBlitz.

3. Cómo editar la información del evento

Los materiales de inicio de este codelab proporcionan cierta estructura para la app web, incluidas algunas hojas de estilo y un par de contenedores HTML para la app. Más adelante en este codelab, conectarás estos contenedores a Firebase.

Para comenzar, familiaricémonos un poco más con la interfaz de StackBlitz.

  1. En StackBlitz, abre el archivo index.html.
  2. Ubica event-details-container y description-container y, luego, edita algunos detalles del evento.

A medida que editas el texto, la recarga automática de la página en StackBlitz muestra los detalles del evento nuevo. Genial, ¿no?

<!-- ... -->

<div id="app">
  <img src="..." />

  <section id="event-details-container">
     <h1>Firebase Meetup</h1>

     <p><i class="material-icons">calendar_today</i> October 30</p>
     <p><i class="material-icons">location_city</i> San Francisco</p>

  </section>

  <hr>

  <section id="firebaseui-auth-container"></section>

  <section id="description-container">
     <h2>What we'll be doing</h2>
     <p>Join us for a day full of Firebase Workshops and Pizza!</p>
  </section>
</div>

<!-- ... -->

La vista previa de tu app debería ser similar a la siguiente:

Vista previa de la app

captura de pantalla de este paso

4. Crea y configura un proyecto de Firebase

Mostrar la información del evento es muy útil para los invitados, pero solo mostrar los eventos no es muy útil para nadie. Agreguemos algunas funcionalidades dinámicas a esta app. Para ello, deberás conectar Firebase a tu app. Para comenzar a usar Firebase, deberás crear y configurar un proyecto de Firebase.

Crea un proyecto de Firebase

  1. Accede a Firebase.
  2. En Firebase console, haz clic en Agregar proyecto (o Crear un proyecto) y, luego, asigna el nombre Firebase-Web-Codelab a tu proyecto de Firebase.

    captura de pantalla de este paso

  3. Haz clic para avanzar por las opciones de creación del proyecto. Acepta las condiciones de Firebase si se te solicita. En la pantalla de Google Analytics, haz clic en "No habilitar" porque no usarás Analytics para esta app.

Para obtener más información sobre los proyectos de Firebase, consulta Información sobre los proyectos de Firebase.

Habilita y configura los productos de Firebase en la consola

La app que compilas usa varios productos de Firebase que están disponibles para aplicaciones web:

  • Firebase Authentication y la IU de Firebase para permitir que los usuarios accedan a tu app con facilidad
  • Cloud Firestore, a fin de guardar datos estructurados en la nube y recibir notificaciones al instante cuando se modifiquen los datos
  • Reglas de seguridad de Firebase para proteger tu base de datos

Algunos de estos productos necesitan una configuración especial o se deben habilitar mediante Firebase console.

Habilita el acceso con correo electrónico para Firebase Authentication

Para permitir que los usuarios accedan a la app web, deberás usar el método de acceso con correo electrónico y contraseña en este codelab:

  1. En el panel lateral izquierdo de Firebase console, haz clic en Build > Authentication. Luego, haz clic en Comenzar. Ahora te encuentras en el panel de Authentication, donde puedes ver los usuarios que se registraron, configurar los proveedores de acceso y administrar la configuración.

    captura de pantalla de este paso

  2. Selecciona la pestaña Método de acceso (o haz clic aquí para ir directamente a la pestaña).

    captura de pantalla de este paso

  3. Haz clic en Correo electrónico/Contraseña en las opciones del proveedor, mueve el interruptor a Habilitar y, luego, haz clic en Guardar.

    captura de pantalla de este paso

Configura Cloud Firestore

La aplicación web usa Cloud Firestore para guardar mensajes de chat y recibir mensajes nuevos.

A continuación, te mostramos cómo configurar Cloud Firestore:

  1. En el panel lateral izquierdo de Firebase console, haz clic en Compilar > Base de datos de Firestore. Luego, haz clic en Crear base de datos.
  2. Haz clic en Crear base de datos.

    captura de pantalla de este paso

  3. Selecciona la opción Comenzar en modo de prueba. Lee la renuncia de responsabilidad sobre las reglas de seguridad. El modo de prueba garantiza que puedas escribir con libertad en la base de datos durante el desarrollo. Haz clic en Next.

    captura de pantalla de este paso

  4. Selecciona la ubicación de tu base de datos (puedes usar la predeterminada). Sin embargo, ten en cuenta que esta ubicación no se puede cambiar más adelante.

    captura de pantalla de este paso

  5. Haz clic en Listo.

5. Agrega y configura Firebase

Ahora que creaste tu proyecto de Firebase y algunos servicios habilitados, debes indicarle al código que deseas usar Firebase y qué proyecto de Firebase usar.

Agrega las bibliotecas de Firebase

Para que tu app use Firebase, debes agregar las bibliotecas de Firebase. Existen varias maneras de hacerlo, como se describe en la documentación de Firebase. Por ejemplo, puedes agregar las bibliotecas desde la CDN de Google o instalarlas localmente con npm y, luego, empaquetarlas en tu app si usas Browserify.

StackBlitz proporciona una agrupación automática para que puedas agregar las bibliotecas de Firebase con instrucciones de importación. Usarás las versiones modulares (v9) de las bibliotecas, que ayudan a reducir el tamaño general de la página web a través de un proceso llamado “eliminación de código no utilizado”. Obtén más información sobre los SDK modulares en los documentos.

Para compilar esta app, usa las bibliotecas de Firebase Authentication, FirebaseUI y Cloud Firestore. En este codelab, las siguientes sentencias de importación ya están incluidas en la parte superior del archivo index.js. A medida que avancemos, importaremos más métodos de cada biblioteca de Firebase:

// Import stylesheets
import './style.css';

// Firebase App (the core Firebase SDK) is always required
import { initializeApp } from 'firebase/app';

// Add the Firebase products and methods that you want to use
import {} from 'firebase/auth';
import {} from 'firebase/firestore';

import * as firebaseui from 'firebaseui';

Agrega una aplicación web de Firebase a tu proyecto de Firebase

  1. Vuelve a Firebase console y haz clic en Descripción general del proyecto, en la parte superior izquierda, para navegar a la página de resumen del proyecto.
  2. En el centro de la página de resumen del proyecto, haz clic en el ícono web ícono de app webpara crear una nueva aplicación web de Firebase.

    captura de pantalla de este paso

  3. Registra la app con el sobrenombre Web App.
  4. En este codelab, NO marques la casilla junto a También configurar Firebase Hosting para esta app. Por el momento, usarás el panel de vista previa de StackBlitz.
  5. Haz clic en Registrar app.

    captura de pantalla de este paso

  6. Copia el objeto de configuración de Firebase en el portapapeles.

    captura de pantalla de este paso

  7. Haz clic en Ir a la consola.Agrega el objeto de configuración de Firebase a tu app:
  8. De regreso en StackBlitz, ve al archivo index.js.
  9. Ubica la línea de comentario Add Firebase project configuration object here y pega el fragmento de configuración justo debajo del comentario.
  10. Agrega la llamada a función initializeApp para configurar Firebase con la configuración única de tu proyecto de Firebase.
    // ...
    // Add Firebase project configuration object here
    const firebaseConfig = {
      apiKey: "random-unique-string",
      authDomain: "your-projectId.firebaseapp.com",
      databaseURL: "https://your-projectId.firebaseio.com",
      projectId: "your-projectId",
      storageBucket: "your-projectId.appspot.com",
      messagingSenderId: "random-unique-string",
      appId: "random-unique-string",
    };
    
    // Initialize Firebase
    initializeApp(firebaseConfig);
    

6. Agregar acceso de usuario (RSVP)

Ahora que agregaste Firebase a la app, puedes configurar un botón para confirmar asistencia que registre a las personas con Firebase Authentication.

Autentica a tus usuarios con el acceso con correo electrónico y FirebaseUI

Necesitarás un botón para confirmar tu asistencia que le pida al usuario que acceda con su dirección de correo electrónico. Para ello, conecta FirebaseUI a un botón de confirmación de asistencia.FirebaseUI es una biblioteca que ofrece una IU precompilada además de Firebase Auth.

FirebaseUI requiere una configuración (consulta las opciones en la documentación) que realice las siguientes dos tareas:

  • Le indica a FirebaseUI que quieres usar el método de acceso con correo electrónico y contraseña.
  • Controla la devolución de llamada para un acceso exitoso y muestra el valor falso para evitar un redireccionamiento. No quieres que la página se actualice porque estás compilando una app web de una sola página.

Agrega el código para inicializar FirebaseUI Auth

  1. En StackBlitz, ve al archivo index.js.
  2. En la parte superior, busca la sentencia de importación firebase/auth y, luego, agrega getAuth y EmailAuthProvider, de esta manera:
    // ...
    // Add the Firebase products and methods that you want to use
    import { getAuth, EmailAuthProvider } from 'firebase/auth';
    
    import {} from 'firebase/firestore';
    
  3. Guarda una referencia al objeto auth justo después de initializeApp, de la siguiente manera:
    initializeApp(firebaseConfig);
    auth = getAuth();
    
  4. Ten en cuenta que la configuración de FirebaseUI ya se proporciona en el código de inicio. Ya está configurado para usar el proveedor de autenticación de correo electrónico.
  5. En la parte inferior de la función main() en index.js, agrega la sentencia de inicialización de FirebaseUI de la siguiente manera:
    async function main() {
      // ...
    
      // Initialize the FirebaseUI widget using Firebase
      const ui = new firebaseui.auth.AuthUI(auth);
    }
    main();
    
    

Agrega un botón para confirmar asistencia en el HTML

  1. En StackBlitz, ve al archivo index.html.
  2. Agrega el código HTML para un botón de confirmación de asistencia dentro de event-details-container, como se muestra en el siguiente ejemplo.

    Asegúrate de usar los mismos valores de id que se muestran a continuación porque, para este codelab, ya hay hooks para estos IDs específicos en el archivo index.js.

    Ten en cuenta que en el archivo index.html hay un contenedor con el ID firebaseui-auth-container. Este es el ID que pasarás a FirebaseUI para mantener tu acceso.
    <!-- ... -->
    
    <section id="event-details-container">
        <!-- ... -->
        <!-- ADD THE RSVP BUTTON HERE -->
        <button id="startRsvp">RSVP</button>
    </section>
    <hr>
    <section id="firebaseui-auth-container"></section>
    <!-- ... -->
    
    Vista previa de la aplicación

    captura de pantalla de este paso

  3. Configura un objeto de escucha en el botón de confirmación de asistencia y llama a la función de inicio de FirebaseUI. Esto le indica a FirebaseUI que quieres ver la ventana de acceso.

    Agrega el siguiente código al final de la función main() en index.js:
    async function main() {
      // ...
    
      // Listen to RSVP button clicks
      startRsvpButton.addEventListener("click",
       () => {
            ui.start("#firebaseui-auth-container", uiConfig);
      });
    }
    main();
    

Prueba acceder a la app

  1. En la ventana de vista previa de StackBlitz, haz clic en el botón Confirmar asistencia para acceder a la aplicación.
    • En este codelab, puedes usar cualquier dirección de correo electrónico, incluso una falsa, ya que no configurarás un paso de verificación por correo electrónico para este codelab.
    • Si ves un mensaje de error que indica auth/operation-not-allowed o The given sign-in provider is disabled for this Firebase project, asegúrate de que habilitaste Correo electrónico/contraseña como proveedor de acceso en Firebase console.
    Vista previa de la app

    captura de pantalla de este paso

  2. Ve al panel Authentication de Firebase console. En la pestaña Usuarios, deberías ver la información de la cuenta que ingresaste para acceder a la app.

    captura de pantalla de este paso

Agrega el estado de autenticación a la IU

Luego, asegúrate de que la IU refleje el hecho de que accediste.

Usarás la devolución de llamada del objeto de escucha de estado de Firebase Authentication, al que se notifica cada vez que cambia el estado de acceso del usuario. Si ya hay un usuario registrado, tu app cambiará el botón “Confirmar asistencia” por un botón “Salir”.

  1. En StackBlitz, ve al archivo index.js.
  2. En la parte superior, busca la sentencia de importación firebase/auth y, luego, agrega signOut y onAuthStateChanged, de esta manera:
    // ...
    // Add the Firebase products and methods that you want to use
    import {
      getAuth,
      EmailAuthProvider,
      signOut,
      onAuthStateChanged
    } from 'firebase/auth';
    
    import {} from 'firebase/firestore';
    
  3. Agrega el siguiente código en la parte inferior de la función main():
    async function main() {
      // ...
    
      // Listen to the current Auth state
      onAuthStateChanged(auth, user => {
        if (user) {
          startRsvpButton.textContent = 'LOGOUT';
        } else {
          startRsvpButton.textContent = 'RSVP';
        }
      });
    }
    main();
    
  4. En el objeto de escucha de botones, verifica si hay un usuario actual y sal de la cuenta. Para ello, reemplaza la startRsvpButton.addEventListener actual con lo siguiente:
    // ...
    // Called when the user clicks the RSVP button
    startRsvpButton.addEventListener('click', () => {
      if (auth.currentUser) {
        // User is signed in; allows user to sign out
        signOut(auth);
      } else {
        // No user is signed in; allows user to sign in
        ui.start('#firebaseui-auth-container', uiConfig);
      }
    });
    

Ahora, el botón de tu app debería mostrar LOGOUT y debería volver a RSVP cuando se hace clic en él.

Vista previa de la app

captura de pantalla de este paso

7. Escriba mensajes en Cloud Firestore

Saber que los usuarios vienen es genial, pero vamos a brindarles a los invitados otra actividad que hacer en la app. ¿Y si pudieran dejar mensajes en un libro de visitas? Pueden compartir por qué están entusiasmados por venir o a quién esperan conocer.

Para almacenar los mensajes de chat que los usuarios escriben en la app, debes usar Cloud Firestore.

Modelo de datos

Cloud Firestore es una base de datos NoSQL. Los datos almacenados en ella se dividen en colecciones, documentos, campos y subcolecciones. Almacenarás cada mensaje del chat como un documento en una colección de nivel superior llamada guestbook.

Gráfico de un modelo de datos de Firestore que muestra una colección de un libro de visitas con varios documentos de mensajes

Agrega mensajes a Firestore

En esta sección, agregarás la funcionalidad para que los usuarios escriban mensajes nuevos en la base de datos. Primero, agregas el código HTML para los elementos de la IU (campo de mensaje y botón para enviar). Luego, agregas el código que vincula estos elementos a la base de datos.

Para agregar los elementos de la IU de un campo de mensaje y un botón de envío, haz lo siguiente:

  1. En StackBlitz, ve al archivo index.html.
  2. Busca el archivo guestbook-container y, luego, agrega el siguiente código HTML para crear un formulario con el campo de entrada de mensajes y el botón de envío.
    <!-- ... -->
    
     <section id="guestbook-container">
       <h2>Discussion</h2>
    
       <form id="leave-message">
         <label>Leave a message: </label>
         <input type="text" id="message">
         <button type="submit">
           <i class="material-icons">send</i>
           <span>SEND</span>
         </button>
       </form>
    
     </section>
    
    <!-- ... -->
    

Vista previa de la app

captura de pantalla de este paso

Los usuarios que hagan clic en el botón ENVIAR activarán el fragmento de código que aparece abajo. Agrega el contenido del campo de entrada del mensaje a la colección guestbook de la base de datos. Específicamente, el método addDoc agrega el contenido del mensaje a un documento nuevo (con un ID generado automáticamente) a la colección guestbook.

  1. En StackBlitz, ve al archivo index.js.
  2. En la parte superior, busca la sentencia de importación firebase/firestore y, luego, agrega getFirestore, addDoc y collection, de esta manera:
    // ...
    
    // Add the Firebase products and methods that you want to use
    import {
      getAuth,
      EmailAuthProvider,
      signOut,
      onAuthStateChanged
    } from 'firebase/auth';
    
    import {
      getFirestore,
      addDoc,
      collection
    } from 'firebase/firestore';
    
  3. Ahora guardaremos una referencia al objeto db de Firestore justo después de initializeApp:
    initializeApp(firebaseConfig);
    auth = getAuth();
    db = getFirestore();
    
  4. En la parte inferior de la función main(), agrega el siguiente código.

    Ten en cuenta que auth.currentUser.uid es una referencia al ID único generado automáticamente que Firebase Authentication proporciona a todos los usuarios que accedieron a sus cuentas.
    async function main() {
      // ...
    
      // Listen to the form submission
      form.addEventListener('submit', async e => {
        // Prevent the default form redirect
        e.preventDefault();
        // Write a new message to the database collection "guestbook"
        addDoc(collection(db, 'guestbook'), {
          text: input.value,
          timestamp: Date.now(),
          name: auth.currentUser.displayName,
          userId: auth.currentUser.uid
        });
        // clear message input field
        input.value = '';
        // Return false to avoid redirect
        return false;
      });
    }
    main();
    

Mostrar el libro de visitas solo a los usuarios que accedieron a sus cuentas

No quieres que cualquiera vea el chat de los invitados. Algo que puedes hacer para proteger el chat es permitir que solo los usuarios registrados vean el libro de visitas. Dicho esto, en el caso de tus propias apps, deberás proteger la base de datos con reglas de seguridad de Firebase. Encontrarás más información sobre las reglas de seguridad más adelante en el codelab.

  1. En StackBlitz, ve al archivo index.js.
  2. Edita el objeto de escucha onAuthStateChanged para ocultar y mostrar el libro de visitas.
    // ...
    
    // Listen to the current Auth state
    onAuthStateChanged(auth, user => {
      if (user) {
        startRsvpButton.textContent = 'LOGOUT';
        // Show guestbook to logged-in users
        guestbookContainer.style.display = 'block';
      } else {
        startRsvpButton.textContent = 'RSVP';
        // Hide guestbook for non-logged-in users
        guestbookContainer.style.display = 'none';
      }
    });
    

Prueba el envío de mensajes

  1. Asegúrate de haber accedido a la app.
  2. Ingresa un mensaje como "¡Hola!" y, luego, haz clic en ENVIAR.

Con esta acción, se escribe el mensaje en tu base de datos de Cloud Firestore. Sin embargo, todavía no verás el mensaje en tu app web real, ya que aún debes implementar la recuperación de datos. Lo harás a continuación.

Sin embargo, puedes ver el mensaje que se acaba de agregar en Firebase console.

En Firebase console, en el panel de la base de datos de Firestore, deberías ver la colección guestbook con el mensaje que acabas de agregar. Si sigues enviando mensajes, tu colección de libro de visitas contendrá muchos documentos, como el siguiente:

Firebase console

captura de pantalla de este paso

8. Lea los mensajes

Cómo sincronizar mensajes

Es bueno que los invitados puedan escribir mensajes en la base de datos, pero que aún no puedan verlos en la app.

Para mostrar mensajes, deberás agregar objetos de escucha que se activen cuando los datos cambien y, luego, crear un elemento de la IU que muestre los mensajes nuevos.

Agregarás código que escuche los mensajes recién agregados desde la app. Primero, agrega una sección en el código HTML para mostrar los mensajes:

  1. En StackBlitz, ve al archivo index.html.
  2. En guestbook-container, agrega una sección nueva con el ID de guestbook.
    <!-- ... -->
    
      <section id="guestbook-container">
       <h2>Discussion</h2>
    
       <form><!-- ... --></form>
    
       <section id="guestbook"></section>
    
     </section>
    
    <!-- ... -->
    

A continuación, registra el objeto de escucha que escucha los cambios realizados en los datos:

  1. En StackBlitz, ve al archivo index.js.
  2. En la parte superior, busca la sentencia de importación firebase/firestore y, luego, agrega query, orderBy y onSnapshot, de esta manera:
    // ...
    import {
      getFirestore,
      addDoc,
      collection,
      query,
      orderBy,
      onSnapshot
    } from 'firebase/firestore';
    
  3. En la parte inferior de la función main(), agrega el siguiente código para hacer un bucle a través de todos los documentos (mensajes del libro de visitas) en la base de datos. Para obtener más información sobre lo que sucede en este código, consulta la información que aparece debajo del fragmento.
    async function main() {
      // ...
    
      // Create query for messages
      const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc'));
      onSnapshot(q, snaps => {
        // Reset page
        guestbook.innerHTML = '';
        // Loop through documents in database
        snaps.forEach(doc => {
          // Create an HTML entry for each document and add it to the chat
          const entry = document.createElement('p');
          entry.textContent = doc.data().name + ': ' + doc.data().text;
          guestbook.appendChild(entry);
        });
      });
    }
    main();
    

Para escuchar los mensajes de la base de datos, creaste una consulta en una colección específica con la función collection. El código anterior escucha los cambios en la colección guestbook, que es donde se almacenan los mensajes de chat. Los mensajes también se ordenan por fecha y se usan orderBy('timestamp', 'desc') para mostrar los más recientes en la parte superior.

La función onSnapshot toma dos parámetros: la consulta que se usará y una función de devolución de llamada. La función de devolución de llamada se activa cuando se realizan cambios en los documentos que coinciden con la consulta. Esto podría suceder si se borra, modifica o agrega un mensaje. Para obtener más información, consulta la documentación de Cloud Firestore.

Prueba la sincronización de mensajes

Cloud Firestore sincroniza los datos de forma automática e instantánea con los clientes suscritos a la base de datos.

  • Los mensajes que creaste anteriormente en la base de datos deberían mostrarse en la app. Puedes escribir mensajes nuevos, ya que deberían aparecer al instante.
  • Si abres tu espacio de trabajo en varias ventanas o pestañas, los mensajes se sincronizarán en tiempo real entre pestañas.
  • (Opcional) Puedes intentar borrar, modificar o agregar mensajes nuevos de forma manual directamente en la sección Base de datos de Firebase console. Todos los cambios deberían aparecer en la IU.

¡Felicitaciones! Estás leyendo documentos de Cloud Firestore en tu app.

Vista previa de la app

captura de pantalla de este paso

9. Configura reglas de seguridad básicas

Inicialmente, configuraste Cloud Firestore para usar el modo de prueba, lo que significa que tu base de datos está abierta para operaciones de lectura y escritura. Sin embargo, solo debes usar el modo de prueba durante las primeras etapas del desarrollo. Como práctica recomendada, debes configurar reglas de seguridad para la base de datos mientras desarrollas la app. La seguridad debe ser una parte fundamental de la estructura y el comportamiento de la app.

Las reglas de seguridad te permiten controlar el acceso a documentos y colecciones de tu base de datos. La sintaxis de reglas flexibles te permite crear reglas que coincidan con todo, desde todas las operaciones de escritura en la base de datos hasta las operaciones en un documento específico.

Puedes escribir reglas de seguridad para Cloud Firestore en Firebase console:

  1. En la sección Compilación de Firebase console, haz clic en Base de datos de Firestore y, luego, selecciona la pestaña Reglas (o haz clic aquí para ir directamente a la pestaña Reglas).
  2. Deberías ver las siguientes reglas de seguridad predeterminadas, con un límite de tiempo de acceso público de un par de semanas a partir de hoy.

captura de pantalla de este paso

Cómo identificar colecciones

Primero, identifica las colecciones en las que la app escribe datos.

  1. Borra la cláusula match /{document=**} existente para que tus reglas se vean de la siguiente manera:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
      }
    }
    
  2. En match /databases/{database}/documents, identifica la colección que deseas proteger:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /guestbook/{entry} {
         // You'll add rules here in the next step.
      }
    }
    

Agrega reglas de seguridad

Debido a que usaste el UID de autenticación como campo en cada documento del libro de visitas, puedes obtener el UID de autenticación y verificar que cualquier persona que intente escribir en el documento tenga un UID de autenticación coincidente.

  1. Agrega las reglas de lectura y escritura a tu conjunto de reglas como se muestra a continuación:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /guestbook/{entry} {
          allow read: if request.auth.uid != null;
          allow create:
            if request.auth.uid == request.resource.data.userId;
        }
      }
    }
    
  2. Haz clic en Publicar para implementar las reglas nuevas.En el caso del libro de visitas, solo los usuarios que hayan iniciado sesión podrán leer los mensajes (cualquier mensaje), pero solo podrás crear un mensaje con tu ID de usuario. Tampoco permitimos que los mensajes se editen ni se borren.

Agregar reglas de validación

  1. Agrega la validación de datos para asegurarte de que todos los campos esperados estén presentes en el documento:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /guestbook/{entry} {
          allow read: if request.auth.uid != null;
          allow create:
          if request.auth.uid == request.resource.data.userId
              && "name" in request.resource.data
              && "text" in request.resource.data
              && "timestamp" in request.resource.data;
        }
      }
    }
    
  2. Haz clic en Publicar para implementar las reglas nuevas.

Cómo restablecer objetos de escucha

Dado que tu app ahora solo permite que accedan los usuarios autenticados, debes mover la consulta firestore del libro de visitas al objeto de escucha de Authentication. De lo contrario, se producirán errores de permisos y la app se desconectará cuando el usuario salga de su cuenta.

  1. En StackBlitz, ve al archivo index.js.
  2. Extrae el objeto de escucha onSnapshot de la colección del libro de visitas a una nueva función llamada subscribeGuestbook. Además, asigna los resultados de la función onSnapshot a la variable guestbookListener.

    El objeto de escucha onSnapshot de Firestore muestra una función para anular la suscripción que podrás usar para cancelar el objeto de escucha de instantáneas más adelante.
    // ...
    // Listen to guestbook updates
    function subscribeGuestbook() {
      const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc'));
      guestbookListener = onSnapshot(q, snaps => {
        // Reset page
        guestbook.innerHTML = '';
        // Loop through documents in database
        snaps.forEach(doc => {
          // Create an HTML entry for each document and add it to the chat
          const entry = document.createElement('p');
          entry.textContent = doc.data().name + ': ' + doc.data().text;
          guestbook.appendChild(entry);
        });
      });
    }
    
  3. Agrega una función nueva debajo llamada unsubscribeGuestbook. Verifica si la variable guestbookListener no es nula y, luego, llama a la función para cancelar el objeto de escucha.
    // ...
    // Unsubscribe from guestbook updates
    function unsubscribeGuestbook() {
      if (guestbookListener != null) {
        guestbookListener();
        guestbookListener = null;
      }
    }
    

Por último, agrega las nuevas funciones a la devolución de llamada onAuthStateChanged.

  1. Agrega subscribeGuestbook() en la parte inferior de if (user).
  2. Agrega unsubscribeGuestbook() en la parte inferior de la sentencia else.
    // ...
    // Listen to the current Auth state
    onAuthStateChanged(auth, user => {
      if (user) {
        startRsvpButton.textContent = 'LOGOUT';
        // Show guestbook to logged-in users
        guestbookContainer.style.display = 'block';
        // Subscribe to the guestbook collection
        subscribeGuestbook();
      } else {
        startRsvpButton.textContent = 'RSVP';
        // Hide guestbook for non-logged-in users
        guestbookContainer.style.display = 'none';
        // Unsubscribe from the guestbook collection
        unsubscribeGuestbook();
      }
    });
    

10. Paso adicional: Practica lo que aprendiste

Cómo grabar el estado de confirmación de asistencia de un asistente

En este momento, la app solo permite que las personas comiencen a chatear si les interesa el evento. Además, la única manera de saber si alguien viene es si lo publica en el chat. Organímonos y hagamos saber cuántas personas vienen.

Agregarás un botón de activación para registrar a las personas que quieran asistir al evento y, luego, recopilarás un recuento de la cantidad de personas que asistirán.

  1. En StackBlitz, ve al archivo index.html.
  2. En guestbook-container, agrega un conjunto de botones y NO, de esta manera:
    <!-- ... -->
      <section id="guestbook-container">
       <h2>Are you attending?</h2>
         <button id="rsvp-yes">YES</button>
         <button id="rsvp-no">NO</button>
    
       <h2>Discussion</h2>
    
       <!-- ... -->
    
     </section>
    <!-- ... -->
    

Vista previa de la app

captura de pantalla de este paso

A continuación, registra el objeto de escucha para los clics en botones. Si el usuario hace clic en , usa su UID de autenticación para guardar la respuesta en la base de datos.

  1. En StackBlitz, ve al archivo index.js.
  2. En la parte superior, busca la sentencia de importación firebase/firestore y, luego, agrega doc, setDoc y where, de esta manera:
    // ...
    // Add the Firebase products and methods that you want to use
    import {
      getFirestore,
      addDoc,
      collection,
      query,
      orderBy,
      onSnapshot,
      doc,
      setDoc,
      where
    } from 'firebase/firestore';
    
  3. En la parte inferior de la función main(), agrega el siguiente código para escuchar el estado de confirmación de asistencia:
    async function main() {
      // ...
    
      // Listen to RSVP responses
      rsvpYes.onclick = async () => {
      };
      rsvpNo.onclick = async () => {
      };
    }
    main();
    
    
  4. A continuación, crea una colección nueva llamada attendees y registra una referencia al documento si haces clic en alguno de los botones Confirmar asistencia. Establece esa referencia en true o false según el botón en el que se haga clic.

    Primero, para rsvpYes:
    // ...
    // Listen to RSVP responses
    rsvpYes.onclick = async () => {
      // Get a reference to the user's document in the attendees collection
      const userRef = doc(db, 'attendees', auth.currentUser.uid);
    
      // If they RSVP'd yes, save a document with attendi()ng: true
      try {
        await setDoc(userRef, {
          attending: true
        });
      } catch (e) {
        console.error(e);
      }
    };
    
    Luego, lo mismo para rsvpNo, pero con el valor false:
    rsvpNo.onclick = async () => {
      // Get a reference to the user's document in the attendees collection
      const userRef = doc(db, 'attendees', auth.currentUser.uid);
    
      // If they RSVP'd yes, save a document with attending: true
      try {
        await setDoc(userRef, {
          attending: false
        });
      } catch (e) {
        console.error(e);
      }
    };
    

Actualiza tus reglas de seguridad

Como ya tienes algunas reglas configuradas, los datos nuevos que agregues con los botones se rechazarán.

Permitir que se agreguen attendees elementos a la colección

Deberás actualizar las reglas para permitir agregar elementos a la colección attendees.

  1. En la colección attendees, dado que usaste el UID de autenticación como nombre del documento, puedes tomarlo y verificar que el uid del remitente sea el mismo que el documento que está escribiendo. Podrás permitir que todos lean la lista de asistentes (ya que allí no hay datos privados), pero solo el creador podrá actualizarla.
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        // ... //
        match /attendees/{userId} {
          allow read: if true;
          allow write: if request.auth.uid == userId;
        }
      }
    }
    
  2. Haz clic en Publicar para implementar las reglas nuevas.

Agregar reglas de validación

  1. Agrega algunas reglas de validación de datos para asegurarte de que todos los campos esperados estén presentes en el documento:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        // ... //
        match /attendees/{userId} {
          allow read: if true;
          allow write: if request.auth.uid == userId
              && "attending" in request.resource.data;
    
        }
      }
    }
    
  2. No olvides hacer clic en Publicar para implementar tus reglas.

(Opcional) Ahora puedes ver los resultados cuando haces clic en los botones. Ve al panel de Cloud Firestore en Firebase console.

Leer el estado de confirmación de asistencia

Ahora que grabaste las respuestas, veamos quién viene y reflejémoslo en la IU.

  1. En StackBlitz, ve al archivo index.html.
  2. En description-container, agrega un nuevo elemento con el ID de number-attending.
    <!-- ... -->
    
     <section id="description-container">
         <!-- ... -->
         <p id="number-attending"></p>
     </section>
    
    <!-- ... -->
    

A continuación, registra el objeto de escucha de la colección attendees y cuenta la cantidad de respuestas YES:

  1. En StackBlitz, ve al archivo index.js.
  2. En la parte inferior de la función main(), agrega el siguiente código para escuchar el estado de confirmación de asistencia y registrar los clics.
    async function main() {
      // ...
    
      // Listen for attendee list
      const attendingQuery = query(
        collection(db, 'attendees'),
        where('attending', '==', true)
      );
      const unsubscribe = onSnapshot(attendingQuery, snap => {
        const newAttendeeCount = snap.docs.length;
        numberAttending.innerHTML = newAttendeeCount + ' people going';
      });
    }
    main();
    

Por último, destaquemos el botón correspondiente al estado actual.

  1. Crea una función que verifique si el UID de autenticación actual tiene una entrada en la colección attendees y, luego, establece la clase de botón en clicked.
    // ...
    // Listen for attendee list
    function subscribeCurrentRSVP(user) {
      const ref = doc(db, 'attendees', user.uid);
      rsvpListener = onSnapshot(ref, doc => {
        if (doc && doc.data()) {
          const attendingResponse = doc.data().attending;
    
          // Update css classes for buttons
          if (attendingResponse) {
            rsvpYes.className = 'clicked';
            rsvpNo.className = '';
          } else {
            rsvpYes.className = '';
            rsvpNo.className = 'clicked';
          }
        }
      });
    }
    
  2. Además, crearemos una función para anular la suscripción. Se usará cuando el usuario salga de su cuenta.
    // ...
    function unsubscribeCurrentRSVP() {
      if (rsvpListener != null) {
        rsvpListener();
        rsvpListener = null;
      }
      rsvpYes.className = '';
      rsvpNo.className = '';
    }
    
  3. Llama a las funciones desde el objeto de escucha de Authentication.
    // ...
    // Listen to the current Auth state
      // Listen to the current Auth state
      onAuthStateChanged(auth, user => {
        if (user) {
          startRsvpButton.textContent = 'LOGOUT';
          // Show guestbook to logged-in users
          guestbookContainer.style.display = 'block';
    
          // Subscribe to the guestbook collection
          subscribeGuestbook();
          // Subscribe to the user's RSVP
          subscribeCurrentRSVP(user);
        } else {
          startRsvpButton.textContent = 'RSVP';
          // Hide guestbook for non-logged-in users
          guestbookContainer.style.display = 'none'
          ;
          // Unsubscribe from the guestbook collection
          unsubscribeGuestbook();
          // Unsubscribe from the guestbook collection
          unsubscribeCurrentRSVP();
        }
      });
    
  4. Intenta acceder con varios usuarios y observa que el recuento aumenta con cada clic adicional en el botón YES.

Vista previa de la app

captura de pantalla de este paso

11. ¡Felicitaciones!

Utilizaste Firebase para compilar una aplicación web interactiva en tiempo real.

Temas abordados

  • Firebase Authentication
  • FirebaseUI
  • Cloud Firestore
  • Reglas de seguridad de Firebase

Próximos pasos

  • ¿Quieres obtener más información sobre el flujo de trabajo para desarrolladores de Firebase? Consulta el codelab del emulador de Firebase para obtener información sobre cómo probar y ejecutar tu app de forma completamente local.
  • ¿Quieres obtener más información sobre otros productos de Firebase? ¿Quizás quieres almacenar los archivos de imagen que suben los usuarios? ¿O enviar notificaciones a tus usuarios? Consulta el codelab web de Firebase para ver un codelab que profundiza en muchos más productos de Firebase para la Web.
  • ¿Quieres obtener más información sobre Cloud Firestore? ¿Quieres obtener más información sobre las subcolecciones y las transacciones? Ve al codelab web de Cloud Firestore para ver un codelab que profundiza en Cloud Firestore. También puedes consultar esta serie de YouTube para conocer Cloud Firestore.

Más información

¿Cómo te fue?

Nos encantaría recibir tus comentarios. Completa un formulario (muy breve) aquí.