Trabajando con JWT

6.1 jwt-decode

Para trabajar con JWT es indispensable pbtener la información que esta codificada dentro del token, para esto necesitamos instalar un nuevo paquete:

npm install jwt-decode --save

Utilizar este paquete es bastante simple:

import jwtDecode from 'jwt-decode'

let token = ... //Obtenemos el token

let tokenDecoded = jwtDecode(token);

6.2 AuthService

Es recomendable crear un servicio para las operaciones de de autenticación.

El token es almacenado utilizando localStorage (https://developer.mozilla.org/es/docs/Web/API/Window/localStorage)

import axios from 'axios'
import jwtDecode from 'jwt-decode'

let api_url = 'http://localhost:5000/api/v1';

function guardarToken(token) {
    localStorage.setItem('__token__', token);
}

function recuperarToken(token) {
    return localStorage.getItem('__token__');
}

function borrarToken() {
    localStorage.removeItem('__token__');
}

class AuthService {
    autenticar(username, password) {
        return axios.post(`${ api_url }/auth/token`, {
            username: username,
            password: password
        }).then(response => {
            guardarToken(response.data.token);
        });
    }

    cerrarSesion() {
        borrarToken();
    }

    obtenerToken() {
        return recuperarToken();
    }

    obtenerTokenDecodificado() {
        let token = recuperarToken();
        return jwtDecode(token);
    }

    tokenValido() {
        let token = recuperarToken();
        if(!token) {
            return false;
        }
        let tokenDecodificado = jwtDecode(token);
        let ahora = Date.now() / 1000;// milisegundos a segundos
        // comparo la fecha de expiración del token con la fecha actual (ambas en UTC)
        return tokenDecodificado.exp > ahora;
    }

    configRouter(router) {
        // Es necesario configurar el router para verificar la validez del token en cada cambio de página
        router.beforeEach((to, from, next) => {
            if (to.matched.some(record => record.meta.auth)) {
                if(!this.tokenValido()) {
                    next({ name: 'login' });
                } else {
                    next();
                }
            } else {
                next();
            }
        });
    }

    // Utilizamos el configurador global de axios.
    configAxios() {
        // Interceptamos todas las peticiones (excepto /auth/token) y le agregamos el encabezado Authorizarion
        axios.interceptors.request.use((request) => {
            if(`${ api_url }/auth/token` !== request.url && 'OPTIONS' !== request.method.toUpperCase()) {
                let token = this.obtenerToken();
                if(token) {
                    if(!request.headers['Authorization']) {
                        request.headers['Authorization'] = 'Bearer ' + token;
                    }
                }
            }
            return request;
        }, (error) => Promise.reject(error));

        // Interceptamos todas las respuestas y borramos el token en caso de un error 401
        axios.interceptors.response.use((response) => {
            if(response.status === 401) {
                borrarToken();
                return Promise.reject(response);
            } else {
                return Promise.resolve(response);
            }
        }, (error) => Promise.reject(error));
    }
}

export default new AuthService();

Es necesario indicar al router para que rutas se necesita verificar autenticación, para lo cual usamos meta:

import login from './pages/login.vue'
import dashboard from './pages/dashboard.vue'
import peliculas from './pages/peliculas.vue'
import personas from './pages/personas.vue'

const routes = [
    {
        name: 'login',
        path: '/login',
        component: login
    },
    {
        name: 'dashboard',
        path: '/',
        component: dashboard,
        meta: { auth: true }
    },
    {
        name: 'peliculas',
        path: '/peliculas',
        component: peliculas,
        meta: { auth: true }
    },
    {
        name: 'personas',
        path: '/personas',
        component: personas,
        meta: { auth: true }
    }
];

export default routes

Debemos hacer las modificaciones necesarias a main.js

import Vue from 'vue'
import VueRouter from 'vue-router'

import app from './app.vue'

import routes from './routes'

import authService from './services/auth-service'

Vue.use(VueRouter);

const router = new VueRouter({
    routes
});

authService.configRouter(router);
authService.configAxios();

new Vue({
    router,
    render: (h) => h(app)
}).$mount('#app');

Por último elaboremos una página de login:

<template>
    <div>
        <h3>Ingresar al sistema</h3>
        <div>
            <div>
                <form @submit.prevent="login">
                    <div>
                        <label for="usuario_username">Nombre de usuario:</label>
                        <input type="text" id="usuario_username" v-model="usuario.username">
                    </div>
                    <div>
                        <label for="usuario_password">Password:</label>
                        <input type="password" id="usuario_password" v-model="usuario.password">
                    </div>
                    <div class="form-group">
                        <button type="submit">Ingresar</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</template>

<script>
import authService from '../services/auth-service'

export default {
    data() {
        return {
            usuario: {}
        }
    },
    methods: {
        login() {
            authService.autenticar(this.usuario.username, this.usuario.password).then(response => {
                this.$router.push({ name: 'dashboard' });
            });
        }
    }
}
</script>

results matching ""

    No results matching ""