Search code examples
vue.jsaxiosvuexvue-router

Access Vuex before Vue route is resolved


What do I have:

  1. router with auth-required routes and public routes
  2. vuex with user's auth state

What do I want: send request to server using axios to check user's auth state before app is loaded (before router is resolved).

router.js:

import Vue from 'vue'
import Router from 'vue-router'
import store from './store'

Vue.use(Router)

const router = new Router({
  ...
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/account',
      name: 'account',
      component: () => import(/* webpackChunkName: "account" */ './views/Account.vue'),
      meta: {
        requiresAuth: true
      }
    }
  ]
})

router.beforeEach((to, from, next) => {
  if (to.matched.some(route => route.meta.requiresAuth)) {
    if (store.state.authStatus)
      next()
    else
      next({name: 'home'})
  } else {
    next()
  }
})

export default router

store.js:

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    authStatus: false
  },
  mutations: {
    setAuthStatus(state, authStatus) {
      state.authStatus = authStatus
    }
  }
})

 axios.get(...)
   .then(response => {
     store.commit('setAuthStatus', true)
   })

export default store

main.js:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

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

My problem: when I enter mydomain.com/acount in browser (app is not loaded before) while being authorized, anyway I got redirect to home. And after redirect I see that I'm authorized (I set up some DOM element inside Home component which is shown only for authorized users).


I've tried this, didn't helped:

store.js:

const store = new Vuex.Store({
  ...
  actions: {
    setAuthStatus({commit}) {
      axios.get(...)
        .then(response => {
          commit('setAuthStatus', true)
        })
    }
  }
})

main.js:

store.dispatch('setAuthStatus').then(() => {
  new Vue({
    router,
    store,
    render: h => h(App)
  }).$mount('#app')
})

Edit: in main.js I tried to go from

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

to

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

and it also didn't helped.


Solution

  • Going around Vanojx1's answer, I solved my question next way.

    store.js:

    const store = new Vuex.Store({
      state: {
        authStatus: axios.get(...).then(response => {
          store.commit('setAuthStatus', true)
        }),
        userAuth: false
      },
      mutations: {
        setAuthStatus(state, authStatus) {
          state.userAuth = authStatus
        }
      }
    })
    

    router.js:

    router.beforeEach((to, from, next) => {
      if (to.matched.some(route => route.meta.requiresAuth)) {
        store.state.authStatus.then(() => {
          //we're getting 200 status code response here, so user is authorized
          //be sure that API you're consuming return correct status code when user is authorized
          next()
        }).catch(() => {
          //we're getting anything but not 200 status code response here, so user is not authorized
          next({name: 'home'})
        })
      } else {
        next()
      }
    })