top of page
Search
  • Writer's picturealeksvp

How to create a simple UI project with login, session management and protected resources




Full code: https://github.com/aleksvp2017/login

Using:

  • Vue;

  • Vuetify

  • Vue-Router

  • Vuex


I'm assuming you do have node installed (if you don't, just go here).


So, the idea is to construct a very simple UI with a couple of routes in a basic menu. One of the routes is going to demand authentication, so if the user is not authenticated, he is going to be redirected to login.


As usual, install Vue and to create a UI project using webpack

npm i vue

vue init webpack-simple


Then, install Vuetify following the instructions here. I suggest you use webpack install (Vuetify is not really needed here, you can use only Vue if you want).


The last two packages you are going to need are Vue-Router and Vuex

npm install vue-router

npm install vuex


Going to start configuring Vuex. It works similarly as a Singleton, a centralized place to put session data. The big difference is that its properties are responsive.


I like to create a folder, store, and put all the files there:

  • state.js - here you put the data you want on your session (in this case, only user) and the name of the cookie

export default { user: null, userCookieName: 'login' }

  • mutation-types - not really needed, it is just a way to standardized access to you properties

export const SET_USER = 'SET_USER'

  • mutation.js - setters for the state properties

import * as types from './mutation-types' export default{ [types.SET_USER](state, payload){ state.user = payload }, }

  • getters.js - the way to acess the properties of your session. loggedIn is going to be used to check if the user is... err... logged in.

export default{ loggedIn(state){ return !!state.user }, cookieName(state){ return state.userCookieName }, }

  • action.js - the way to change the session properties adding some logic. You may find odd that I have to separated methods, ActionSetUser and ActionLogin, but I need like this, because ActionSetUser is going to be called to reconstruct the session / state using the cookie when the user reload the page. Otherwise, user would need to log in again.Oh, Autenticador.js just returns a "user" (in real life should be a call to some API passing real credentials).

import * as types from './mutation-types' import {login} from '../services/Autenticador.js' import Vue from 'vue' import VueResource from 'vue-resource' Vue.use(VueResource) export const ActionSetUser = (context, payload) => { context.commit(types.SET_USER, payload) localStorage.setItem(context.getters.cookieName, JSON.stringify(payload)) Vue.http.interceptors.push((request, next) => { request.headers.set('Authorization', 'Bearer ' + payload.token) request.headers.set('Accept', 'application/json') next() }); } export const ActionLogin = (context, payload) => { return login(payload).then(res => { context.dispatch('ActionSetUser', res) }) } export const ActionLogout = (context, payload) => { localStorage.removeItem(context.getters.cookieName) location.reload() } export default{ ActionSetUser, ActionLogin, ActionLogout }

  • index.js - is just to make it easy to use all the state stuff with one import

import Vue from 'vue' import Vuex from 'vuex' import state from './state' import mutations from './mutations' import actions from './actions' import getters from './getters' Vue.use(Vuex) export default new Vuex.Store({ state, mutations, actions, getters })




Let's create three vue components (actually there is a 4th component, Navigation.vue, but there isn't anything really interesting about it, just setting a menu using the routes):

<template> <div> Home </div> </template>


and


<template> <div> Unprotected page </div> </template>


and (I choose not to put fields to collect user and password because I'm not really validating those, just faking it)


<template> <div> <v-btn color="primary" class="white--text" @click="login">Login</v-btn> </div> </template>


Now the routes (routes.js):


import VueRouter from 'vue-router' import Vue from 'vue' import Login from './views/login/Login.vue' import Unprotected from './views/unprotected/Unprotected.vue' import Home from './views/home/Home.vue' var routes = [ { path: '/', name: 'Login', component: Login, requireAuth: false}, { path: '/home', name: 'Home', component: Home, requireAuth: true}, { path: '/unprotected', name: 'Unprotected', component: Unprotected, requireAuth: false}, ]; Vue.use(VueRouter) const router = new VueRouter({ routes}); function getRoute(name){ return routes.filter(router => router.name == name)[0] } function routeRequireAuth(path){ let secureRoute = routes.filter(route => route.requireAuth && route.path == path) return secureRoute.length > 0 } export { router, routes, getRoute, routeRequireAuth }


Login is configured as the initial page. Home is set as requiring authentication (requireAuth: true) and Unprotected as not requiring authentication. You have to import and tell Vue Global Object to use the router (going to show main.js code in a minute).


Now, add the script bellow to Login.vue. We're importing mapActions from Vuex, wich give us all the actions (we're just using ActionLogin). Also importing routes to redirect user to Home page after the loggin.

<script> import {mapActions} from 'vuex' import {getRoute} from '../../routes.js' export default { data() { return { credencial :{ }, } }, methods : { ...mapActions(['ActionLogin']), login(){ this.ActionLogin(this.credencial).then((response) => { this.$router.push(getRoute('Home')) }).catch (error => { console.log('Error: ', error) }) }, } } </script>


Now, main.js. There are a few things to do:

  • Import routes and tell Vue to use it;

  • Import store (as there is a index.js file on the folder, you can import the folder) and tell Vue to use it;

  • Create a function (manageProtectedEndPoints) that will check every route: if the URI requires authentication (as configures in routes.js) and user is not logged in, sent it to login;

  • Before do the checking, call updateSessionStateUsingLocalStorage to reconstruct the session if there is a cookie (in real life, you should check if the token is valid).

import Vue from 'vue' import App from './App.vue' import vuetify from './plugins/vuetify' import {router, routeRequireAuth} from './routes.js' import store from './store' manageProtectedEndPoints() new Vue({ el: '#app', store, router, vuetify, render: h => h(App) }) function manageProtectedEndPoints() { updateSessionStateUsingLocalStorage() router.beforeEach((to, from, next) => { if (routeRequireAuth(to.fullPath)) { if (!store.getters.loggedIn) { next('/') return } } if (to.fullPath === '/') { if (store.getters.loggedIn) { next('/home') return } } next() }) } function updateSessionStateUsingLocalStorage() { const userString = localStorage.getItem(store.getters.cookieName) if (userString) { const userData = JSON.parse(userString) store.dispatch('ActionSetUser', userData) } }

When everything is set, you can see that, if you do not click login button and click on Unprotected item on the menu, you're going to be redirected to login.


Of course, unless you have static content that needs to be protected, all you really need is to protect your endpoints on the backend, not in the frontend. But I, personally think is a good practice and nice touch to the final user to do that.










18 views0 comments

Comments


Post: Blog2_Post
bottom of page