Abordar la autenticación con Vue mediante API RESTful | Programar Plus

La autenticación (¡iniciar sesión!) Es una parte crucial de muchos sitios web. Veamos cómo hacerlo en un sitio que usa Vue, de la misma manera que se puede hacer con cualquier back-end personalizado. En realidad, Vue no puede realizar la autenticación por sí solo; necesitaremos otro servicio para eso, por lo que usaremos otro servicio (Firebase) para eso, pero luego integraremos toda la experiencia en Vue.

La autenticación funciona de manera bastante diferente en las aplicaciones de página única (SPA) que en los sitios que recargan cada página. No tienes que hacer un SPA con Vue, pero lo haremos en este tutorial.

Este es el plan. Crearemos una interfaz de usuario para que los usuarios inicien sesión y los datos enviados se enviarán a un servidor para verificar si el usuario existe. Si es así, se nos enviará un token. Eso es muy útil, porque se usará en todo nuestro sitio para verificar si el usuario aún está registrado. Si no, el usuario siempre puede registrarse. En otras palabras, se puede utilizar en muchos contextos condicionales. Más allá de eso, si necesitamos alguna información del servidor que requiera haber iniciado sesión, el token se envía al servidor a través de la URL para que la información solo se pueda enviar a los usuarios registrados.

La demostración completa de este tutorial está publicada en GitHub para aquellos que se sienten cómodos leyendo el código. El resto de nosotros puede seguir adelante con el artículo. El archivo de inicio también está en GitHub para que pueda seguir mientras codificamos juntos.

Después de descargar el repositorio, ejecutará npm install en tu terminal. Si va a crear esta aplicación completamente por su cuenta, tendrá que instalar Vuex, Vue Router y axios. También usaremos Firebase para este proyecto, así que tómate un momento para configurar una cuenta gratuita y crear un nuevo proyecto allí.

Después de agregar el proyecto a Firebase, vaya a la sección de autenticación y configure un método de inicio de sesión en el que usaríamos el proveedor de correo electrónico / contraseña tradicional, que se almacenará en nuestros servidores de Firebase.

Después de eso, iremos a la documentación de la API REST de Firebase Auth para registrarnos e iniciar sesión en los puntos finales de la API. Necesitaremos una clave de API para usar esos extremos en nuestra aplicación y se puede encontrar en la configuración del proyecto de Firebase.

Firebase ofrece autenticación a través del SDK, pero usamos la API de autenticación para demostrar la autenticación en cualquier servidor back-end personalizado.

En nuestro archivo de stater, tenemos el formulario de registro a continuación. Estamos manteniendo las cosas bastante simples aquí, ya que nos enfocamos en aprender los conceptos.

<template>
  <div id="signup">
    <div class="signup-form">
      <form @submit.prevent="onSubmit">
        <div class="input">
          <label for="email">Mail</label>
          <input
             type="email"
             id="email"
             v-model="email">
        </div>
        <div class="input">
          <label for="name">Your Name</label>
          <input
            type="text"
            id="name"
            v-model.number="name">
        </div>
        <div class="input">
          <label for="password">Password</label>
          <input
            type="password"
            id="password"
            v-model="password">
        </div>
        <div class="submit">
          <button type="submit">Submit</button>
        </div>
      </form>
    </div>
  </div>
</template>

Si no estuviéramos trabajando con un SPA, naturalmente usaríamos axios para enviar nuestros datos dentro de la etiqueta del script de esta manera:

axios.post('https://identitytoolkit.googleapis.com/v1/account
  s:signUp?key=[API_KEY]', {
    email: authData.email,
    password: authData.password,
    returnSecureToken: true
  })
  .then(res => {
    console.log(res)
  })
  .catch(error => console.log(error))        
  }
}

Regístrese e inicie sesión

Trabajar con un SPA (usando Vue en este caso) es muy diferente del enfoque anterior. En cambio, enviaremos nuestras solicitudes de autorización utilizando Vuex en nuestras acciones en el store.js Archivo. Lo estamos haciendo de esta manera porque queremos que toda la aplicación esté al tanto de cualquier cambio en el estado de autenticación del usuario.

actions: {
  signup ({commit}, authData) {
    axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]', {
      email: authData.email,
      password: authData.password,
      returnSecureToken: true
    })
    .then(res => {
      console.log(res)
      router.push("/dashboard")
    })
    .catch(error => console.log(error))
  },
  login ({commit}, authData) {
    axios.post(https://identitytoolkit.googleapis.com/v1/accounts:signIn?key=[API_KEY]', {
      email: authData.email,
      password: authData.password,
      returnSecureToken: true
    })
    .then(res => {
      console.log(res)
      router.push("/dashboard")
    })
    .catch(error => console.log(error))
  }
}

Podemos usar prácticamente lo mismo para el método de inicio de sesión, pero usando el punto final de la API de inicio de sesión en su lugar. Luego enviamos tanto el registro como el inicio de sesión desde los componentes, a sus respectivas acciones en la tienda.

methods : { 
  onSubmit () {
    const formData = {
      email : this.email,
      name : this.name,     
      password : this.password
    }
    this.$store.dispatch('signup', formData)
    }
  }
}

formData contiene los datos del usuario.

methods : {
  onSubmit () {
    const formData = {
      email : this.email,
      password : this.password
    }
    this.$store.dispatch('login', {email: formData.email, password: formData.password})
  }
}

Estamos tomando los datos de autenticación (es decir, el token y la identificación del usuario) que se recibieron del formulario de registro / inicio de sesión y los usamos como estado con Vuex. Inicialmente resultará como null.

state: {
  idToken: null,
  userId: null,
  user: null
}

Ahora creamos un nuevo método llamado authUser en las mutaciones que almacenarán los datos recopilados de la respuesta. Necesitamos importar el enrutador a la tienda, ya que lo necesitaremos más adelante.

import router from '/router'


mutations : {
  authUser (state, userData) {
    state.idToken = userData.token
    state.userId = userData.userId
  }
}

Dentro de .then bloquear los métodos de registro / inicio de sesión en nuestras acciones, confirmaremos nuestra respuesta a la authUser mutación recién creada y guardada en el almacenamiento local.

actions: {
  signup ({commit}, authData) {
    axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]'), {
      email: authData.email,
      password: authData.password,
      returnSecureToken: true
    })
    .then(res => {
      console.log(res)
      commit('authUser', {
        token: res.data.idToken,
        userId: res.data.localId
      })
      localStorage.setItem('token', res.data.idToken)
      localStorage.setItem('userId', res.data.localId)
      router.push("/dashboard")
    })
    .catch(error => console.log(error))
  },
  login ({commit}, authData) {
    axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signIn?key=[API_KEY]'), {
      email: authData.email,
      password: authData.password,
      returnSecureToken: true
    })
    .then(res => {
      console.log(res)
      commit('authUser', {
        token: res.data.idToken,
        userId: res.data.localId
      })
        localStorage.setItem('token', res.data.idToken)
        localStorage.setItem('userId', res.data.localId)
        router.push("/dashboard")
      })
    .catch(error => console.log(error))
  }
}

Configurar una protección de autenticación

Ahora que tenemos nuestro token almacenado dentro de la aplicación, usaremos este token mientras configuramos nuestro Auth guard. ¿Qué es un protector de autenticación? Protege el panel de control de usuarios no autenticados que acceden a él sin tokens.

Primero, ingresaremos en nuestro archivo de ruta e importaremos la tienda. La tienda se importa debido al token que determinará el estado de inicio de sesión del usuario.

import store from './store.js'

Luego, dentro de nuestra matriz de rutas, vaya a la ruta del tablero y agregue el método beforeEnter que toma tres parámetros: to, from y next. Dentro de este método, simplemente estamos diciendo que si los tokens se almacenan (lo cual se hace automáticamente si se autentican), entonces next, lo que significa que continúa con la ruta designada. De lo contrario, estamos dirigiendo al usuario no autenticado a la página de registro.

{
  path: '/dashboard',
  component: DashboardPage,
  beforeEnter (to, from, next) {
    if (store.state.idToken) {
      next()
    } 
    else {
      next('/signin')
    }
  }
}

Creando el estado de la interfaz de usuario

En este punto, todavía podemos ver el tablero en la navegación, ya sea que estemos conectados o no, y eso no es lo que queremos. Tenemos que agregar otro método bajo los captadores llamado ifAuthenticated que comprueba si el token dentro de nuestro estado es nully, a continuación, actualice los elementos de navegación en consecuencia.

getters: {
  user (state) {
    return state.user
  },
  ifAuthenticated (state) {
    return state.idToken !== null
  }
}

A continuación, abramos el componente de encabezado y creemos un método llamado auth dentro de computed propiedad. Que se enviará a la ifAuthenticated captadores que acabamos de crear en la tienda. ifAuthenticated volverá false si no hay token, lo que significa automáticamente auth también sería null, y viceversa. Después de eso, agregamos un v-if para comprobar si auth es null o no, determinar si la opción del panel de control se mostraría en la navegación.

<template>
  <header id="header">
    <div class="logo">
      <router-link to="https://css-tricks.com/">Vue Authenticate</router-link>
    </div>
    <nav>
      <ul>
        <li v-if="auth">
          <router-link to="/dashboard">Dashboard</router-link>
        </li>
        <li  v-if="!auth">
          <router-link to="/signup">Register</router-link>
        </li>
        <li  v-if="!auth">
          <router-link to="/signin">Log In</router-link>
        </li>
      </ul>
    </nav>
  </header>
</template>
<script>
  export default {
    computed: {
      auth () {
        return this.$store.getters.ifAuthenticated
      }
    },
  }
</script>

Saliendo de tu cuenta

¿Qué es una aplicación sin un botón para cerrar sesión? Creemos una nueva mutación llamada clearAuth, que establece tanto el token como userId a null.

mutations: {
  authUser (state, userData) {
    state.idToken = userData.token
    state.userId = userData.userId
  },
  clearAuth (state) {
    state.idToken = null
    state.userId = null
  }
}

Entonces, en nuestro logout acción, nos comprometemos a clearAuth, elimine el almacenamiento local y agregue router.replace("https://css-tricks.com/") para redirigir correctamente al usuario después del cierre de sesión.

Volver al componente de encabezado. Tenemos una onLogout método que envía nuestro logout acción en la tienda. Luego agregamos un @click al botón que llama al onLogout método como podemos ver a continuación:

<template>
  <header id="header">
    <div class="logo">
      <router-link to="https://css-tricks.com/">Vue Authenticate</router-link>
    </div>
    <nav>
      <ul>
        <li v-if="auth">
          <router-link to="/dashboard">Dashboard</router-link>
        </li>
        <li  v-if="!auth">
          <router-link to="/signup">Register</router-link>
        </li>
        <li  v-if="!auth">
          <router-link to="/signin">Log In</router-link>
        </li>
         <li  v-if="auth">
          <ul @click="onLogout">Log Out</ul>
        </li>
      </ul>
    </nav>
  </header>
</template>
<script>
  export default {
    computed: {
      auth () {
        return this.$store.getters.ifAuthenticated
      }
    },
    methods: {
      onLogout() {
        this.$store.dispatch('logout')
      }
    }
  }
</script>

¿Ingreso automático? ¡Seguro!

Casi hemos terminado con nuestra aplicación. Podemos registrarnos, iniciar sesión y cerrar sesión con todos los cambios en la interfaz de usuario que acabamos de realizar. Pero, cuando actualizamos nuestra aplicación, perdemos los datos y cerramos la sesión, teniendo que comenzar de nuevo porque almacenamos nuestro token y nuestra identificación en Vuex, que es JavaScript. Esto significa que todo en la aplicación se vuelve a cargar en el navegador cuando se actualiza.

Lo que haremos es recuperar el token dentro de nuestro almacenamiento local. Al hacer eso, podemos tener el token del usuario en el navegador independientemente de cuándo actualice la ventana, e incluso iniciar sesión automáticamente con el usuario siempre que el token siga siendo válido.

Crea un nuevo método de acciones llamado AutoLogin, donde obtendremos el token y userId del almacenamiento local, solo si el usuario tiene uno. Luego, enviamos nuestros datos al authUser método en las mutaciones.

actions : {
  AutoLogin ({commit}) {
    const token = localStorage.getItem('token')
    if (!token) {
      return
    }
    const userId = localStorage.getItem('userId')
    const token = localStorage.getItem('token')
    commit('authUser', {
      idToken: token,
      userId: userId
    })
  }
}

Luego vamos a nuestro App.vue y hacer un created método donde enviaremos el autoLogin de nuestra tienda cuando se carga la aplicación.

created () {
  this.$store.dispatch('AutoLogin')
}

¡Hurra! Con eso, hemos implementado con éxito la autenticación dentro de nuestra aplicación y ahora podemos implementar usando npm run build. Vea la demostración en vivo para verla en acción.

El sitio de ejemplo es únicamente para fines de demostración. No comparta datos reales, como su correo electrónico y contraseña reales, mientras prueba la aplicación de demostración.

(Visited 3 times, 1 visits today)