I want some code to be ran before anything else in the app, that code will send a request to the Back-end and then update the store. I need that part to be executed first because route guards depend on it, how to achieve that?
Code Example
Fetching user information & settings
async init() {
await AuthService.initCSRF();
await AuthService.getUser().then((res) => {
if (res.data && res.data.user) {
this.loginLocally(res.data.user);
} else {
this.logoutLocally();
}
});
}
Auth guard
export function isLoggedIn(to, from, next) {
console.log('Checked', store.state.auth.isLoggedIn);
if (store.state.auth.isLoggedIn) {
next();
return;
}
next({ name: 'login' })
}
CodePudding user response:
in my old project, I did something like this. hope you get some idea.
app.js
import App from './components/App.vue'
store.dispatch('auth/attempt', sessionStorage.getItem('token')).then(() =>{
new Vue({
el: '#app',
router,
store,
render: h => h(App),
});
});
here I'm validating the token saved in local storage before rendering the app.
my Vuex actions something like this
async signIn({dispatch}, credentials) {
let response = await axios.post("auth/signin", credentials);
await dispatch('attempt', response.data.token)
},
async attempt({commit, state}, token) {
if (token) {
await commit('SET_TOKEN', token);
}
if (!state.token) {
return;
}
try {
let response = await axios.get('auth/me');
commit('SET_USER', response.data)
} catch (e) {
commit('SET_TOKEN', null);
commit('SET_USER', null);
}
},
async signOut({commit}) {
axios.post('auth/signout').then(() => {
commit('SET_TOKEN', null);
commit('SET_USER', null);
});
}
I'm using a subscriber to listen to mutations and add or remove token in request headers
import store from '../store'
store.subscribe((mutation) => {
if (mutation.type === 'auth/SET_TOKEN') {
if (mutation.payload) {
axios.defaults.headers.common['Authorization'] = `Bearer ${mutation.payload}`;
sessionStorage.setItem('token', mutation.payload);
} else {
axios.defaults.headers.common['Authorization'] = null;
sessionStorage.removeItem('token');
}
}
});
Finally an axios interceptor for handle token expiration.
import router from '../plugins/router'
import store from '../store'
import axios from "axios";
axios.interceptors.response.use((response) => {
return response;
}, (error) => {
if (error.response.status) {
if (error.response.status === 401) {
if (router.currentRoute.name !== 'landing') {
store.dispatch('auth/clearToken').then(() => {
router.replace({
name: 'landing'
});
}).finally(() => {
swal.fire(
'Your Session is Expired',
'Please sign in again!',
'error'
)
});
}
}
}
return Promise.reject(error);
});
CodePudding user response:
Initialization promise can be waited before calling .mount(...)
. The problem is that Vue router starts separately from the application and won't be delayed this way.
If it's the router that depends on initialization process, a way to delay router start is to wait for the promise in router hook that is triggered before other ones:
const initPromise = init();
...
router.beforeEach(async (to, from, next) => {
await initPromise;
next();
});