Access the store in routes.js to use navigation guards





  • I do it like this:
    Example route (router/routes.js):

          {
            path: 'live-view',
            name: 'live-view',
            component: () => import('pages/LiveView'),
            meta: {
              requiresAuth: true,
              permissions: ['liveview']
            }
          },
    

    Then, in routes/index.js:

    Router.beforeEach((to, from, next) => {
      let allowedToEnter = true
      to.matched.some((record) => {
        // check if there is meta data
        let isLoggedIn = store.getters['auth/isLoggedIn']
        if (!isLoggedIn && record.name === 'home') {
          next({
            path: '/sign-in',
            replace: true
          })
          return
        }
    
        if ('meta' in record) {
          // ------------------------------------------------------------
          // check if user needs to be logged in to access this page
          if ('requiresAuth' in record.meta) {
            if (record.meta.requiresAuth) {
              // console.log('Page requires auth:', to, from)
              // this route requires auth, check if user is logged in
              // if not, redirect to login page.
              if (!isLoggedIn) {
                // User is not logged in, redirect to signin page
                allowedToEnter = false
                next({
                  path: '/sign-in',
                  replace: true,
                  // redirect back to original path when done signing in
                  query: { redirect: to.fullPath }
                })
              }
            }
          }
          // ------------------------------------------------------------
          // check if user has correct permissions to access this page
          if (allowedToEnter && 'permissions' in record.meta) {
            let canProceed = false
            let permissions = record.meta.permissions
            // get currently logged in user permissions
            let token = store.getters['auth/token']
            // decipher the token
            let session = JWT.read(token)
            // check if they are not an admin (administrator)
            if (session.claim.permissions.administrator) {
              canProceed = true
            }
            else {
              for (let index = 0; index < permissions.length; ++index) {
                let permission = permissions[index]
                // console.log('Permission needed:', permission)
                if (permission === 'administrator') {
                  if (session.claim.permissions.administrator) {
                    canProceed = true
                  }
                }
                else if (permission === 'liveview') {
                  if (session.claim.permissions.liveview) {
                    canProceed = true
                  }
                }
    ...
    


  • If you don’t want the checks in your route index.js file, you could also put them into a quasar plugin file called guards.js or something and get the same result. That keeps your index.js file cleaner. Either should work but the plugin model has the added effect of being able to seperate them if desired and quickly turn things on/off by simply commenting out the plugin name(s) in quasar.conf.js when needed.



  • @hawkeye64

    Thanks for the example, a question ?, did not you need to import the store to be able to use it? Because I try to use it directly and I do not have access to it.

    This is the store in which I am testing, it is a function that is being exported, I am maintaining as function it because the idea is to be able to use it with SSR. When I import this store and access to state from here vuex does not work properly.

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    import example from './module-example';
    
    import config from './config/config';
    
    Vue.use(Vuex);
    
    /*
     * If not building with SSR mode, you can
     * directly export the Store instantiation
     */
    
    export default function (/* { ssrContext } */) {
      const Store = new Vuex.Store({
        state: {
          value: 0,
        },
        getters: {
          value: state => state.value,
        },
        mutations: {
          updateValueMut: (state, payload) => {
            state.value = payload;
          },
        },
        actions: {
          updateValueAct({ commit }, payload) {
            commit('updateValueMut', payload);
          },
        },
      });
    
      return Store;
    }
    


  • @genyded
    Thanks, I just saw the documentation about the plugins, apparently the store is accessible directly from here.



  • @Gonzalo2683
    My complete index.js in the router folder:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    import routes from './routes'
    import store from '../store'
    
    import JWT from 'jwt-client'
    
    Vue.use(VueRouter)
    
    const Router = new VueRouter({
      /*
       * NOTE! Change Vue Router mode from quasar.conf.js -> build -> vueRouterMode
       *
       * If you decide to go with "history" mode, please also set "build.publicPath"
       * to something other than an empty string.
       * Example: '/' instead of ''
       */
    
      // Leave as is and change from quasar.conf.js instead!
      mode: process.env.VUE_ROUTER_MODE,
      base: process.env.VUE_ROUTER_BASE,
      scrollBehavior: () => ({ y: 0 }),
      routes
    })
    
    Router.beforeEach((to, from, next) => {
      let allowedToEnter = true
      to.matched.some((record) => {
        // check if there is meta data
        let isLoggedIn = store.getters['auth/isLoggedIn']
        if (!isLoggedIn && record.name === 'home') {
          next({
            path: '/sign-in',
            replace: true
          })
          return
        }
    
        if ('meta' in record) {
          // ------------------------------------------------------------
          // check if user needs to be logged in to access this page
          if ('requiresAuth' in record.meta) {
            if (record.meta.requiresAuth) {
              // console.log('Page requires auth:', to, from)
              // this route requires auth, check if user is logged in
              // if not, redirect to login page.
              if (!isLoggedIn) {
                // User is not logged in, redirect to signin page
                allowedToEnter = false
                next({
                  path: '/sign-in',
                  replace: true,
                  // redirect back to original path when done signing in
                  query: { redirect: to.fullPath }
                })
              }
            }
          }
          // ------------------------------------------------------------
          // check if user has correct permissions to access this page
          if (allowedToEnter && 'permissions' in record.meta) {
            let canProceed = false
            let permissions = record.meta.permissions
            // get currently logged in user permissions
            let token = store.getters['auth/token']
            // decipher the token
            let session = JWT.read(token)
            // check if they are not an admin (administrator)
            if (session.claim.permissions.administrator) {
              canProceed = true
            }
            else {
              for (let index = 0; index < permissions.length; ++index) {
                let permission = permissions[index]
                // console.log('Permission needed:', permission)
                if (permission === 'administrator') {
                  if (session.claim.permissions.administrator) {
                    canProceed = true
                  }
                }
                else if (permission === 'liveview') {
                  if (session.claim.permissions.liveview) {
                    canProceed = true
                  }
                }
                else if (permission === 'archive') {
                  if (session.claim.permissions.archive) {
                    canProceed = true
                  }
                }
                else if (permission === 'alarmsArchiveEvents') {
                  if (session.claim.permissions.alarmsArchiveEvents) {
                    canProceed = true
                  }
                }
                else if (permission === 'remoteAccess') {
                  if (session.claim.permissions.remoteAccess) {
                    canProceed = true
                  }
                }
                else if (permission === 'settings') {
                  if (session.claim.permissions.settings) {
                    canProceed = true
                  }
                }
                else {
                  console.error('Unknown permission in Router.beforeEach:', permission)
                }
              }
            }
    
            if (!canProceed) {
              allowedToEnter = false
              // redirect to not-authorized page
              next({
                path: '/not-authorized',
                replace: true
              })
            }
          }
        }
      })
    
      if (allowedToEnter) {
        // go to the requested page
        next()
      }
    })
    
    export default Router
    


  • In conjuntion with this, I also wrote middleware on the server side that receives the JWT for each axios call and then validates it in the routes as well.



  • @Hawkeye64 With which version of quasar are you using this. I have a very strange issue, accessing the store in the router (same spirit as you are doing it) is possible in 0.15.15 but it fails in 0.17.17.
    An idea?



  • Quasar CLI........ v0.17.19
    Quasar Framework.. v0.17.16