Vue/Quasar Authentication & Authorization - Thu, Jul 22, 2021
Secure your application updating your Vue Router. Add Role-Based Access Control easily.
Notes
- Example used on Vue/Quasar projects using localStorage.
- Expects the user object to have an array of strings, each one represents a role
{ roles: ["user"] } - Redirects to /login on failure with param
redirectTo
How to
- Create and copy the file
src/plugins/auth.js - Update you
quasar.conf.jsplugins property - Update your
src/router/routes.js, each vue route can have ametaproperty- We will use
requiresAuth(boolean) andallowedRoles([string array])
- We will use
Route Example
{
path: '/',
component: () => import('layouts/MyLayout.vue'),
meta: {
requiresAuth: true, allowedRoles: ['user', 'admin']
},
children: [
{ path: 'user/my-profile', component: () => import('pages/user/my-profile.vue') }
]
}
Functions
validateAxiosAuthHeaderis used as a hotfix on production, tech debt no documentation except that it was related to reloading the browser processvalidateRouteAuthenticationworks using localStorage itemtoken, check if is null or notvalidateRouteAuthorizationworks using localStorage itemuser, the propertyrolesfrom the user object, RBAC-like
src/plugins/auth.js
import { Notify } from 'quasar'
import { axios } from './axios'
const notifyAuthenticationError = (message) => Notify.create({
color: 'negative',
position: 'top',
icon: 'report_problem',
message: `Error de autentificación: ${message || 'Por favor revisa tus permisos'}`
})
function validateAxiosAuthHeader (to, from, next) {
const jsonWebToken = localStorage.getItem('token')
if (jsonWebToken) {
localStorage.setItem('token', jsonWebToken)
axios.setJsonWebToken(jsonWebToken)
}
next()
}
// to, from and next and route objects (see https://router.vuejs.org/api/#the-route-object)
// router.matched or to.matched
// returns an Array containing route records for
// all nested path segments of the current route.
// Array.prototype.some()
// tests whether at least one element in the array passes the test implemented by the provided function.
function validateRouteAuthentication (to, from, next) {
const requiresAuthorization = to.matched.some(route => route.meta.requiresAuth)
const jsonWebToken = localStorage.getItem('token')
// this route requires auth
if (requiresAuthorization) {
if (jsonWebToken) {
return next()
} else {
const redirect = {
path: '/login',
query: { redirect: to.fullPath }
}
console.log(`validateRouteAuthentication failed, redirecting to ${redirect.path} (trying to access ${redirect.query.redirect})`)
notifyAuthenticationError('Por favor inicia sesión con tus credenciales de Softtek')
return next(redirect)
}
}
// route doesn't require authentication
return next()
}
function validateRouteAuthorization (to, from, next) {
const requiresAuthorization = to.matched.some(route => route.meta.allowedRoles)
const user = JSON.parse(localStorage.getItem('user'))
// this route requires auth
if (requiresAuthorization) {
for (var i = 0; i < to.matched.length; i++) {
const route = to.matched[i]
if (route.allowedRoles) {
const userHasValidRole = route.meta.allowedRoles.some(allowedRole => user.roles.some(userRole => userRole === allowedRole))
if (userHasValidRole) {
return next()
} else {
const redirect = {
path: '/login',
query: { redirect: to.fullPath }
}
console.log(`validateRouteAuthorization failed, redirecting to ${redirect.path} (trying to access ${redirect.query.redirect})`)
notifyAuthenticationError('No autorizado')
return next(redirect)
}
}
}
}
// route doesn't require authentication
return next()
}
// leave the export, even if you don't use it
export default ({ app, router, Vue }) => {
router.beforeEach(validateAxiosAuthHeader)
router.beforeEach(validateRouteAuthentication)
router.beforeEach(validateRouteAuthorization)
}