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();
});
