1
votes

Having a dashboard app created with vuejs and vue-router most of my routes are requiring authentication and I want to catch globally if token is expired and route back in that case to login component.

Right now router looks as it follows

import Vue from 'vue'
import VueRouter from 'vue-router'
import AttendersView from '@/views/AttendersView.vue'
import LoginView from '@/views/LoginView.vue'
import store from '../store'
import log from '@/middleware/log'
Vue.use(VueRouter)

const routes = [
  {
    path: '*',
    meta: {
      name: '',
      requiresAuth: true
    },
    redirect: {
      path: '/attenders'
    }
  },
  {
    path: '/login',
    component: LoginView,
    meta: {
      guest: true
    },
    children: [
      {
        path: '',
        component: () => import('@/components/LoginForm.vue')
      }
    ]
  },
  {
    path: '/',
    meta: {
      name: 'Dashboard View',
      requiresAuth: true
    },
    component: () => import('@/views/DashboardView.vue'),
    children: [
      {
        path: '/attenders',
        name: 'Anmeldungen',
        component: AttendersView,
        meta: {
          requiresAuth: true,
          middleware: log
        }
      },
      {
        path: '/organizations',
        name: 'Verbände',
        meta: {
          requiresAuth: true,
          middleware: log
        },
        component: () => import(/* webpackChunkName: "about" */ '../views/OrganizationsView.vue')
      },
      {
        path: '/workgroups',
        name: 'Arbeitsgruppen',
        meta: {
          requiresAuth: true,
          middleware: log
        },
        component: () => import(/* webpackChunkName: "about" */ '../views/WorkgroupsView.vue')
      },
      {
        path: '/status',
        name: 'Status',
        meta: {
          requiresAuth: true,
          middleware: log
        },
        component: () => import(/* webpackChunkName: "about" */ '../views/StatusView.vue')
      }
    ]
  }
]

const router = new VueRouter({
  mode: 'history',
  base: 'dashboard',
  routes,
  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    }
    if (to.hash) {
      return { selector: to.hash }
    }
    return { x: 0, y: 0 }
  }
})

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    if (store.getters.authorized) {
      next()
      return
    }
    next('/login')
  } else {
    next()
  }
})

export default router

and here is my custom request.js

import axios from 'axios'

class HttpClient {
  constructor (token) {
    if (localStorage.getItem('token')) {
      token = localStorage.getItem('token')
    }
    const service = axios.create({
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`
      }
    })

    this.service = service
  }

  redirectTo = (document, path) => {
    document.location = path
  }

  get (path) {
    return this.service.get(path)
  }

  patch (path, payload, callback) {
    return this.service
      .request({
        method: 'PATCH',
        url: path,
        responseType: 'json',
        data: payload
      })
  }

  post (path, payload) {
    return this.service.request({
      method: 'POST',
      url: path,
      responseType: 'json',
      data: payload
    })
  }

  delete (path, payload) {
    return this.service.request({
      method: 'DELETE',
      url: path,
      responseType: 'json',
      data: payload
    })
  }

  download (path) {
    return this.service.request({
      method: 'POST',
      url: path,
      responseType: 'blob'
    })
  }
}
const HttpRequests = new HttpClient()
export default HttpRequests

and right now I'm doing like this in component to catch 401

methods: {
    fetchInitialData: function () {
      this.isLoading = true
      HttpClient.get(API_ATTENDERS_ENDPOINT).then(resp => {
        this.attenders = resp.data.attenders
        this.organizations = resp.data.organizations
        this.workgroups = resp.data.workgroups
        this.isLoading = false
      }).catch(error => {
        if (error.response.status === 401) {
          this.$store.dispatch('logout')
        }
      })
    }

but I need something generic.

What is the best approach and where should I place an axios interceptor ?

1

1 Answers

0
votes

What you can do is use navigation guards for this task: https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards

Before the user enters any of the routes you want Authentication attached to then you can have a before enter, and then check their privileges.

Pass then on with a next() if they succeed or throw them to the login.