What do I have:
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.
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()
}
})
In the navigation guard you need something async so save your axios promise in the store as authStatus. When it resolves commit and set the loggedIn status. In the navigation guard wait for the promise to be resolved and then call the next function to enter the next router.
Store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
/* EXAMPLE
authStatus: new Promise(resolve => {
setTimeout(() => {
const requestResult = true;
store.commit("setAuthStatus", requestResult);
resolve(requestResult);
}, 1000);
}),
*/
authStatus: axios.get(...).then((requestResult) => {
store.commit("setAuthStatus", requestResult);
}),
loggedIn: false
},
mutations: {
setAuthStatus(state, loggedIn) {
state.loggedIn = loggedIn;
}
}
});
export default store;
router.js
router.beforeEach((to, from, next) => {
if (to.matched.some(route => route.meta.requiresAuth)) {
store.state.authStatus.then(loggedIn => {
if (loggedIn) next();
else next({ name: "home" });
});
} else {
next();
}
});
Check this solution working here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With