Axios interceptor and router push not working
-
I am trying to push users back to the login page if authentication fails. However in a Axios interceptor the router push doesn’t seem to work. Are there good any other ways that i can deal with a authentication fail?
import Vue from 'vue' import axios from 'axios' import store from '../store'; // request interceptor axios.interceptors.request.use( config => { const token = store().getters['auth/accessToken']; if (token) { config.headers['Authorization'] = 'Bearer ' + token; } return config; }, error => { Promise.reject(error) }); // response interceptor axios.interceptors.response.use((response) => { return response }, function (error) { if (error.response.status === 401 && !window.refreshing) { window.refreshing = true; return axios.post('http://posadmin/api/auth/refresh', { "refresh_token": store().getters['auth/refreshToken'] }) .then(res => { console.log(res.status); console.log(res.data); if (res.status === 200) { store().commit("auth/refreshToken", res.data); axios.defaults.headers.common['Authorization'] = 'Bearer ' + store().getters['auth/accessToken']; return axios(error.config); } else { console.log('200 else'); store().dispatch("auth/setLogout"); this.$router.push('/login'); } }) .catch((error) => { console.log(window.refreshing); console.log('catch '+error); store().dispatch("auth/setLogout"); this.$router.push('/login'); }); } // return Error object with Promise return Promise.reject(error); }); Vue.prototype.$axios = axios;
-
You can simply use
window.location = '/#/login'
-
Does it work? What @jraez said should help.
If you really want to use the router, you can do that, too.
The code you showed is in a boot file, right? So I think yourthis.$router.push('/login')
call doesn’t work becausethis.$router
is not defined. Normally, you write that in a Vue component, wherethis
refers to the component - but you are in a boot file.This is how you can do it:
import axios from "axios" export default ({ Vue, router }) => { // <-------- This is where the `router` comes from Vue.prototype.$axios = axios; // ... (your request interceptor here) axios.interceptors.response.use(response => { return response; }, error => { if (error.response.status === 401) { // ... router.push("/login"); // <---- note there is no `this` } // ... }); }
-
Quick note: Vue warn again calling VueX methods such as dispatch or commit outside of a Vue component. Example:
store().commit("auth/refreshToken", res.data);
-
Hello!
Were you able to make router.push work?
I can’t seem to get it to work.‘’’
import Vue from ‘vue’
import axios from ‘axios’
import { Notify } from ‘quasar’
import router from ‘…/router’const axiosInstance = axios.create({
baseURL: process.env.API
})axiosInstance.interceptors.response.use(response => {
return response
}, error => {
if (error.response.status === 401) {
Notify.create({
type: ‘negative’,
timeout: 1000,
position: ‘top’,
message: error.response.data.message
})
router.push(’/login’)
return Promise.reject(error)
}
})Vue.prototype.$axios = axiosInstance
export { axiosInstance }‘’’
-
@mflorindo router is passed as an argument inside your bootfile https://quasar.dev/quasar-cli/boot-files#Anatomy-of-a-boot-file. or you can expose it from your src/router/index.js file. like this
let router = null export default function ({ store }) { router = new VueRouter({ ... }) ... return router } export { router } //somefile.js then you can import it import { router } from '…/router’
-
BTW,
router.push({ name: 'dashboard' })
will throw a promise error but this will pass:router.push({ path: '/dashboard' }, () => { })
-
Sorry for coming back very late to this topic, however the router intercept is very sensitive. Using window.location, dispatching/committing data in vuex or any other logics in the intercept are all very inconsistent. The users were experiencing different data in their localstorage than in their browser. I ended up with the following.
import VueRouter from 'vue-router' import routes from './routes' import store from 'src/store' const router = new VueRouter({ // This will make the page scroll to top for all route navigations. scrollBehavior: () => ({x: 0, y: 0}), routes, mode: process.env.VUE_ROUTER_MODE, base: process.env.VUE_ROUTER_BASE }); const routingServiceChecks = async (to, from, next) => { const requiresAuth = to.matched.some(route => route.meta.requiresAuth); const accessToken = store().getters['auth/accessToken']; // authenticated check if (requiresAuth && accessToken === null) { return next('/login'); } // always go to the next route next(); }; router.beforeEach(routingServiceChecks); export default router
I moved all other logics to the base layout or other components. I made a separate service which I catch seperately once the data retrieval is initiated and fails. Refreshing tokens I moved to a global function which is initiated on a failure of retrieving any data, persisting the new tokens to the localstorage after that has been 100% successful.
here is an example of my login function and refresh without the use of interception:
async onSubmit() { await this.$store.dispatch('instance/loading', true); if (this.$v.$invalid) { await this.$store.dispatch('instance/loginFailed', this.$t('login.empty')); } else { await this.$auth.login(this.login).then(response => { if (response.status === 200) { this.$store.dispatch('auth/loginSuccess', response.data).then(() => { if(this.redirect !== '') { router.push({name: this.redirect}, onComplete => {}, onAbort => {}) } else { router.push({name: 'home'}, onComplete => {}, onAbort => {}) } }); } else { this.$store.dispatch('instance/loginFailed', this.$t('text.login.failed')) } }).catch(error => { this.$store.dispatch('instance/loginFailed', this.$t('text.' + Mixins.error('login', error.response.status)) ); }) } await this.$store.dispatch('instance/loading', false); }
attemptRefresh (type) { this.$auth.refresh().then(response => { // set refresh to success this.$store.dispatch('auth/setRefreshSuccess', response.data).then(() => { switch (type) { case 'core': this.core() break; case 'sync': this.sync() break; } }) }).catch(() => { this.setError(false, true) }) }