Search code examples
vue.jsnavigationvue-routerbrowser-historyvue-i18n

Vue router - navigation guard is skipped when using router.push()


I have a Vue SPA with i18n and some views that require authentication via navigation guard.

When i am not authenticated and go to url via my browser:

 examplepage.com/en/lockedpage

i get redirected to:

    examplepage.com/en/login 

which is good, however when i click a button that runs:

  @click="$router.push(`/${$i18n.locale}/lockedpage`)"

i get in to the page even if i am not authenticated. I want to get redirected to the login page if not authenticated

this is my router.js:

  import Vue from 'vue';
  import Router from 'vue-router';
  import Home2 from './views/Home2.vue';
  import Login from './views/Login.vue';
  import Register from './views/Register.vue';
  import ErrorLanding from './views/ErrorLanding.vue'
  import Root from "./Root"
  import i18n, { loadLocaleMessagesAsync } from "@/i18n"
  import {
   setDocumentLang
  } from "@/util/i18n/document"

 Vue.use(Router);

 const { locale } = i18n


 export const router = new Router({
   mode: 'history',
   base: '/',
    routes: [
      {
        path: '/',
        redirect: locale
      },
      {
        path: "/:locale",
        component: Root,
        children: [
      {
        name: 'Home',
        path: '',
        component: Home2,
      },
      {
        name: 'Home2',
        path: '/',
        component: Home2,
      },
      {
        name: 'Login',
        path: 'login',
        component: Login,
      },
      {
        path: 'register',
        component: Register,
      },
      {
        path: 'lockedpage',
        name: 'lockedpage',
        webpackChunkName: "lockedpage",
        meta: {authRequired: true},
        component: () => import('./views/LockedPage.vue')
       },
       {
       path: '*',
       component: ErrorLanding,
       name: 'NotFound'
       }
     ]
   }
   ],

 router.beforeEach((to, from, next) => {
   if (to.params.locale === from.params.locale) {
     next()
     return
   }

  const { locale } = to.params

   loadLocaleMessagesAsync(locale).then(() => {
     setDocumentLang(locale)
   const publicPages = [ `/`, `/${locale}`, `/${locale}/`];
   const authRequired = !publicPages.includes(to.path);
   const loggedIn = localStorage.getItem('user');
   const redirect = to.path;


     if (authRequired && loggedIn === null) {
       if(to.meta.authRequired === false) {
         next();
      }
    else
    next({ name: 'Login', query: { redirect: redirect } });

     } else {
      next();
      }
    })

   next()

   });

Why does my navigationguard skip when using router.push() ? This issue started after adding i18n, with localeredirect. so all routes comes after a locale for example: /en/.../


Solution

  • As Estus points out in the comments, the issue is that the first thing you're checking for is if the locales match, and if they do you're calling next() and sending the user to the page.

    As outlined here:

    Make sure that the next function is called exactly once in any given pass through the navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors.

    If you need to keep the locale check between the to and from pages, you could do something like:

    if (to.params.locale === from.params.locale && loggedIn) {
         next()
         return
       }
    

    which will check if the loggedIn variable is truthy before pushing the user to the page they're trying to navigate to.

    I believe just removing the if statement that checks if the locales match would also work.