Anuncio de Cloud Firestore (Beta): Prueba la nueva base de datos escalable y flexible de Firebase y Google Cloud Platform. Obtén más información sobre Cloud Firestore.

Seguridad basada en usuarios

En este documento, se revisará los conceptos relacionados con la Protección de tus datos y agregaremos el uso de la variable auth predefinida para crear una solución completa de protección.

Integración de Authentication

Firebase Authentication se integra con Firebase Realtime Database para permitirte controlar el acceso a los datos por usuario.

Cuando se autentica un usuario, se completa la variable auth de las reglas de Firebase Database con la información del usuario. Esta información incluye el identificador único (uid) junto con los datos de la cuenta vinculada, como un ID de Facebook o una dirección de correo electrónico y otra información. Si implementas un proveedor de autenticación personalizado, puedes agregar tus propios campos a la carga útil de autenticación del usuario.

Esta guía explica cómo combinar el lenguaje de reglas de Firebase Realtime Database con la información de autenticación de los usuarios. Puedes combinar estos dos conceptos para controlar el acceso a los datos según la identidad del usuario.

La variable auth

La variable auth predefinida de las reglas tiene un valor nulo antes de la autenticación. Una vez que se autentica el usuario con Firebase Authentication, la variable contiene los siguientes atributos:

provider El método de autenticación usado ("password", "anonymous", "facebook", "github", "google" o "twitter").
uid Un ID de usuario único entre todos los proveedores.
token El contenido del token de ID de Firebase Auth. Consulta la documentación de referencia de auth.token para ver más detalles.

Esta es una regla de ejemplo que usa la variable auth para garantizar que cada usuario solo pueda escribir en una ruta específica del usuario:

{
  "rules": {
    "users": {
      "$user_id": {
        // grants write access to the owner of this user account
        // whose uid must exactly match the key ($user_id)
        ".write": "$user_id === auth.uid"
      }
    }
  }
}

Estructuración de la base de datos

A veces resulta útil estructurar tu base de datos de una manera que facilite la escritura de reglas de seguridad. A modo de ejemplo, un patrón común para el almacenamiento de datos de usuario en Realtime Database es almacenar todos los usuarios en un solo nodo users cuyos elementos secundarios son los valores de uid de cada usuario. Si deseas restringir el acceso a estos datos para que solo los usuarios que acceden puedan ver sus propios datos, tus reglas tendrían el siguiente aspecto:

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth != null && auth.uid == $uid"
      }
    }
  }
}

Cómo trabajar con tokens de autenticación personalizados

Si deseas un mayor grado de control, Firebase Authentication permite que los programadores creen sus propios tokens de autenticación personalizados en sus servidores.

De manera opcional, los programadores que crean sus propios tokens de autenticación personalizados pueden agregarles reclamaciones adicionales. Estas reclamaciones adicionales estarán presentes en la variable auth.token de tus reglas. A continuación, se muestra un ejemplo de reglas que usan la reclamación personalizada hasEmergencyTowel:

{
  "rules": {
    "frood": {
      // A towel is about the most massively useful thing an interstellar
      // hitchhiker can have
      ".read": "auth.token.hasEmergencyTowel === true"
    }
  }
}

El SDK de Admin también te permite configurar reclamaciones de token personalizadas para definir funciones de usuario para el control de acceso. Consulta Control de acceso con reclamaciones personalizadas y reglas de seguridad.

Revisión del ejemplo de chat

Volvamos al ejemplo de chat de Cómo proteger tus datos y agreguemos la autenticación de usuarios para reunir todos estos conceptos en una app funcional:

{
  "rules": {
    "room_names": {
      // any logged in user can get a list of room names
      ".read": "auth !== null",

      "$room_id": {
        // this is just for documenting the structure of rooms, since
        // they are read-only and no write rule allows this to be set
        ".validate": "newData.isString()"
      }
    },

    "members": {
       // I can join or leave any room (otherwise it would be a boring demo)
       // I can have a different name in each room just for fun
       "$room_id": {
          // any member can read the list of member names
          ".read": "data.child(auth.uid).exists()",

          // room must already exist to add a member
          ".validate": "root.child('room_names/'+$room_id).exists()",

          "$user_id": {
             ".write": "auth.uid === $user_id",
             ".validate": "newData.isString() && newData.val().length > 0 && newData.val().length < 20"
          }
       }
    },

    "messages": {
      "$room_id": {
        // the list of messages for a room can be read by any member
        ".read": "root.child('members/'+$room_id+'/'+auth.uid).exists()",

        // room we want to write a message to must be valid
        ".validate": "root.child('room_names/'+$room_id).exists()",

        "$message_id": {
          // a new message can be created if it does not exist, but it
          // cannot be modified or deleted
          // any member of a room can write a new message
          ".write": "root.child('members/'+$room_id+'/'+auth.uid).exists() && !data.exists() && newData.exists()",

          // the room attribute must be a valid key in room_names/ (the room must exist)
          // the object to write must have a name, message, and timestamp
          ".validate": "newData.hasChildren(['user', 'message', 'timestamp'])",

          // the message must be written by logged in user
          "user": {
             ".validate": "newData.val() === auth.uid"
          },

          // the message must be longer than 0 chars and less than 50
          "message": { ".validate": "newData.isString() && newData.val().length > 0 && newData.val().length < 50" },

          // messages cannot be added in the past or the future
          // clients should use firebase.database.ServerValue.TIMESTAMP
          // to ensure accurate timestamps
          "timestamp": { ".validate": "newData.val() <= now" },

          // no other fields can be included in a message
          "$other": { ".validate": false }
        }
      }
    }
  }
}

Pasos siguientes

Enviar comentarios sobre...

Firebase Realtime Database
Si necesitas ayuda, visita nuestra página de asistencia.