Accessing authenticated route with vue-router - vuejs2

Ive been struggling with a bug that occurs occasionally within my VueJs2 application.
After i login and im authenticated within my app and data is stored within Vuex then im unable to access an authenticated route when clicking on the link.
The problem is with the 'profile' route which is on my navbar when logged in. If i refresh the browser then it works and im able to click the link and view the component.
The problem is with the beforeEach and it failing to get the Vuex authenticated as true.
This is my current router setup.
import Vue from 'vue'
import VueRouter from 'vue-router'
import { store } from '../store/index'
import SiteIndex from '#/components/home/Index.vue'
import AuctionIndex from '#/components/auction/Index.vue'
import ViewVehicle from '#/components/vehicle/View.vue'
import Login from '#/components/authentication/Login.vue'
import Register from '#/components/registration/Register.vue'
import ForgotPassword from '#/components/authentication/Forgot.vue'
import Cart from '#/components/cart/Index.vue'
import UserProfile from '#/components/user/Profile.vue'
import AboutUs from '#/components/site/About.vue'
import Faq from '#/components/site/Faq.vue'
import HowItWorks from '#/components/site/HowItWorks.vue'
import ContactUs from '#/components/site/ContactUs.vue'
import Terms from '#/components/site/Terms.vue'
import Error404 from '#/components/site/Error404.vue'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/index' },
{ path: '/logout', redirect: '/login' },
{
path: '/index',
name: 'home',
component: SiteIndex,
meta: {
breadcrumb: 'Home',
displayBreadCrumb:false
}
},
{
path: '/auction',
name: 'auction',
component: AuctionIndex,
meta: {
breadcrumb: {
label: 'Auction',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/auction/:slug/:vehicle_id',
component: ViewVehicle,
meta: {
displayBreadCrumb:true
}
},
{
path: '/cart',
component: Cart,
meta: {
requiresAuth: true,
breadcrumb: {
label: 'Basket',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/login',
component: Login,
meta: {
breadcrumb: {
label: 'Login',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/register',
component: Register,
meta: {
breadcrumb: {
label: 'Register',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/forgot',
component: ForgotPassword,
meta: {
breadcrumb: {
label: 'Forgot Password',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/profile',
component: UserProfile,
meta: {
requiresAuth: true,
breadcrumb: {
label: 'My Profile',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/terms',
component: Terms,
meta: {
breadcrumb: {
label: 'Terms and conditions',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/howitworks',
component: HowItWorks,
meta: {
breadcrumb: {
label: 'How it works',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/faq',
component: Faq,
meta: {
breadcrumb: {
label: 'Frequently asked questions',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/about',
component: AboutUs,
meta: {
breadcrumb: {
label: 'About us',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '/contactus',
component: ContactUs,
meta: {
breadcrumb: {
label: 'Contact us',
parent: 'home'
},
displayBreadCrumb:true
}
},
{
path: '*',
component: Error404
}
],
linkActiveClass: 'active',
mode: 'history'
})
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
if(requiresAuth && !store.getters.isLoggedIn) {
next('/login');
} else {
next();
}
})
export default router

Related

Uncaught error missing param when using named router-link

I am following a YouTube course, and I encountered an error on the last part where I added a button for the EditClient route. I'm getting an Uncaught (in promise) Error: Missing required param "id".
router/index.js:
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Dashboard from '../views/dashboard/Dashboard.vue'
import MyAccount from '../views/dashboard/MyAccount.vue'
import SignUp from '../views/SignUp.vue'
import Login from '../views/Login.vue'
import Clients from '../views/dashboard/Clients.vue'
import Client from '../views/dashboard/Client.vue'
import AddClient from '../views/dashboard/AddClient.vue'
import EditClient from '../views/dashboard/EditClient.vue'
import EditTeam from '../views/dashboard/EditTeam.vue'
import Invoices from '../views/dashboard/Invoices.vue'
import Invoice from '../views/dashboard/Invoice.vue'
import AddInvoice from '../views/dashboard/AddInvoice.vue'
import store from '../store'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/sign-up',
name: 'SignUp',
component: SignUp
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/dashboard',
name: 'Dashboard',
component: Dashboard,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/invoices',
name: 'Invoices',
component: Invoices,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/invoices/add',
name: 'AddInvoice',
component: AddInvoice,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/invoices/:id',
name: 'Invoice',
component: Invoice,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/clients',
name: 'Clients',
component: Clients,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/clients/add',
name: 'AddClient',
component: AddClient,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/clients/:id',
name: 'Client',
component: Client,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/clients/:id/edit',
name: 'EditClient',
component: EditClient,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/my-account',
name: 'MyAccount',
component: MyAccount,
meta: {
requireLogin: true
}
},
{
path: '/dashboard/my-account/edit-team',
name: 'EditTeam',
component: EditTeam,
meta: {
requireLogin: true
}
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requireLogin) && !store.state.isAuthenticated) {
next('/login')
}
else {
next()
}
})
export default router
My router link is as follows:
<router-link :to="{ name: 'EditClient', params: { id: client.id }}" class="button is-light mt-4">Edit</router-link>
I have tried, and it works:
<router-link :to="'/dashboard/clients/' + client.id + '/edit'" class="button is-light mt-4">Edit</router-link>
answer by Pylinux from this question.
Although the solution is already acceptable, I would like to know why this is happening in my case.

Signin page redirect to 404 when first load vue js 2.0

When the application starts, I am setting the default path to users, if authentication fails, then it will navigate to sign in. But it redirects to 404.
const routes = [
{
path: "/signin",
name: "signIn",
component: () => import("#/path"),
},
{
.........
},
{
.......
},
{
path: "/",
redirect: "/users",
component: adminLayout,
//needed for nav gaurd
//meta: { requiresAuth: true },
children: [
{
path: "dashboard",
name: "dashboard",
component: dashboard,
meta: {
title: 'Dashbaord'
}
},
{
path: "users",
component: () => import("path"),
meta: {
title: 'Users'
},
children: [
{
path: "",
component: () => import("path"),
meta: {
title: ''
}
},
{
path: ":id/profile",
component: () => import("path"),
meta: {
title: 'Profile'
}
},
]
},
],
},
{
path: "*",
redirect: "/404",
},
{
// the 404 route, when none of the above matches
path: "/404",
name: "404",
component: () => import("#path"),
},
];
If i set redirect: "/dashboard" or redirect: "/signin",, then it works fine.
Also if I navigate to the right path, like "http://localhost:8080/signin" it will work. But if I only type "http://localhost:8080" hit enter it will go to 404 page
Note : first my users component like this and its works fine
{
path: "users",
component: () => import("path"),
meta: {
title: 'Users'
},
},
{
path: ":id/profile",
component: () => import("path"),
meta: {
title: 'Profile'
},
},
Please help me to understand the issue.

Problem when I want to access a component from an external link vue router

I need to recover the password of the users via email, the problem is that when I pass a link via email for example http://my-domain/recovery-password/token, it always redirects me to my login component (http://my-domain/login), what I need is go directly to my recovery-password component. I'm a little new in vue and I don't know what I need to change, this is my code in the router:
const routes = [
{
path: '/',
name: 'home',
component: Home,
meta: {
user_type: 1
}
},
{
path: '/check-balance',
name: 'check-balance',
component: CheckBalanceComponent,
meta: {
user_type: 1
}
},
{
path: '/check-payment',
name: 'check-payment',
component: CheckPaymentsComponent,
meta: {
user_type: 1
}
},
{
path: '/payment-disabled',
name: 'payment-disabled',
component: DisabledMakePaymentComponent,
meta: {
user_type: 1
}
},
{
path: '/handle-payment',
name: 'handle-payment',
component: HandlePaymentsComponent,
meta: {
user_type: 1
}
},
{
path: '/handle-report',
name: 'handle-report',
component: HandleReportsComponent,
meta: {
user_type: 1
}
},
{
path: '/user-profile',
name: 'user-profile',
component: UserProfileComponent,
meta: {
user_type: 1
}
},
{
path: '/login',
name: 'login',
component: LoginComponent,
meta: {
free: 1
}
},
{
path: '/recover-link',
name: 'recover-link',
component: RecoverLinkComponent,
meta: {
free: 1
}
},
{
path: '/recover-password',
name: 'recover-password',
component: RecoverPasswordComponent,
meta: {
free: 1
}
},
{
path: '/help',
name: 'help',
component: HelpComponent,
meta: {
user_type: 1
}
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
if(to.matched.some(record => record.meta.free)){
next()
} else if(store.state.user && store.state.user.user_type == 1){
next()
// } else if(to.matched.some(record => record.meta.fuera)){
// next({
// name: 'recover-password'
// })
} else {
next({
name: 'login'
})
}
})
export default router
I would appreciate your help because I have been standing for a long time without finding a solution
I think Vue looks through all the routes to find which one has free prop as part of its meta object.
And it always find Login route first before it ever gets to recover-password route - its reading top to bottom in the Routes Array.
So, try putting recover-password route before login route like so:
{
path: '/recover-password',
name: 'recover-password',
component: RecoverPasswordComponent,
meta: {
free: 1
}
},
{
path: '/login',
name: 'login',
component: LoginComponent,
meta: {
free: 1
}
}
However, you may start encountering that recover component renders in places where you may need login component.
So, the best way to solve this whole issue is by giving a different free value to both routes and then check for that value in your beforeEach hook.
#nishkaush
This is my vue router code with the changes you suggested to me:
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home,
meta: {
user_type: 1
}
},
{
path: '/check-balance',
name: 'check-balance',
component: CheckBalanceComponent,
meta: {
user_type: 1
}
},
{
path: '/check-payment',
name: 'check-payment',
component: CheckPaymentsComponent,
meta: {
user_type: 1
}
},
{
path: '/payment-disabled',
name: 'payment-disabled',
component: DisabledMakePaymentComponent,
meta: {
user_type: 1
}
},
{
path: '/handle-payment',
name: 'handle-payment',
component: HandlePaymentsComponent,
meta: {
user_type: 1
}
},
{
path: '/handle-report',
name: 'handle-report',
component: HandleReportsComponent,
meta: {
user_type: 1
}
},
{
path: '/user-profile',
name: 'user-profile',
component: UserProfileComponent,
meta: {
user_type: 1
}
},
{
path: '/recover-password',
name: 'recover-password',
component: RecoverPasswordComponent,
meta: {
other: 1
}
},
{
path: '/recover-link',
name: 'recover-link',
component: RecoverLinkComponent,
meta: {
free: 1
}
},
{
path: '/login',
name: 'login',
component: LoginComponent,
params: {
recovery_email: 'email'
},
meta: {
free: 1
}
},
{
path: '/help',
name: 'help',
component: HelpComponent,
meta: {
user_type: 1
}
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
if(to.matched.some(record => record.meta.free)){
next()
}
else if(store.state.user && store.state.user.user_type == 1){
next()
}
/*This is where I have to call my recover-password component,
from an external link without redirecting to the login*/
else if(to.matched.some(record => record.meta.other)){
next()
}
else {
next({
name: 'login'
})
}
})
export default router

Vue router - When replacing route view renders on top of another

When trying to replace the current /login route with another route, it seems that the new route gets rendered on top of the last, making it behave strange.
router.js
const router = new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Main Page',
component: MainPage,
redirect: 'front-page',
children: [
{
path: 'front-page',
name: 'Front page',
component: FrontPage,
meta: {
requireAuth: true,
},
},
{
path: 'home',
name: 'Home page',
component: HomePage,
meta: {
requireAuth: true,
},
},
],
},
{
path: '/profile',
name: 'Profile page',
component: UserProfilePage,
meta: {
requireAuth: true,
},
},
{
path: '/login',
name: 'Login page',
component: LoginPage,
meta: {
requireAuth: false,
},
},
{
path: '/register',
name: 'Registration page',
component: RegistrationPage,
meta: {
requireAuth: false,
},
},
],
});
login.vue
result() {
if (this.loginQuery.sessionToken) {
this.setAuthToken(this.loginQuery.sessionToken);
this.$router.replace('/front-page');
}
},
Your problem may come from redirection,It's no necessary to set 'home' as a default route by using redirect,try code below:
const router = new Router({
mode: 'history',
routes: [
{
name: 'Main Page',
component: MainPage,
children: [
{
path: '/front-page',
name: 'Front page',
component: FrontPage,
meta: {
requireAuth: true,
},
},
{
path: '/',
name: 'Home page',
component: HomePage,
meta: {
requireAuth: true,
},
},
],
},
{
path: '/profile',
name: 'Profile page',
component: UserProfilePage,
meta: {
requireAuth: true,
},
},
{
path: '/login',
name: 'Login page',
component: LoginPage,
meta: {
requireAuth: false,
},
},
{
path: '/register',
name: 'Registration page',
component: RegistrationPage,
meta: {
requireAuth: false,
},
},
],
});

How to use nprogress with vuejs code splitting?

I'm new in vuejs and I want to use nprogress with vuejs code splitting features. Basically I want nprogress when use navigate to pages. The requirement is show progress until component promise not resolve. How can I add this feature in my app?
Here is my code:
import Vue from 'vue'
import Router from 'vue-router'
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css';
// layout components
import Full from '../container/Full'
function asyncComponent(importComponent) {
return importComponent()
Nprogress.start();
importComponent().then(() => {
Nprogress.done();
return importComponent();
})
}
// dashboard components
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
component: Full,
redirect: '/dashboard/dashboard-v1',
children: [
{
path: '/dashboard/dashboard-v1',
component: asyncComponent(() => import('../views/dashboard/DashboardOne')),
meta: {
title: 'Dashboard V1',
breadcrumb: 'Dashboard / Dashboard V1'
}
},
{
path: '/dashboard/dashboard-v2',
component: asyncComponent(() => import('../views/dashboard/DashboardTwo')),
meta: {
title: 'Dashboard V2',
breadcrumb: 'Dashboard / Dashboard V2'
}
}
]
},
{
path: '/session/sign-up',
component: asyncComponent(() => import('../views/SignUp')),
meta: {
title: 'Sign Up',
breadcrumb: 'Session / Sign Up'
}
},
{
path: '/session/login',
component: asyncComponent(() => import('../views/Login')),
meta: {
title: 'Login',
breadcrumb: 'Session / Login'
}
},
{
path: '/session/lock-screen',
component: asyncComponent(() => import('../views/LockScreen')),
meta: {
title: 'Lock Screen',
breadcrumb: 'Session / Lock Screen'
}
}
]
})
NProgress functionality basically work with page routing like, each route changes NProgress loader triggered and it has been written like below,
import Vue from 'vue'
import Router from 'vue-router'
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css';
// layout components
import Full from '../container/Full'
function asyncComponent(importComponent) {
return importComponent()
Nprogress.start();
importComponent().then(() => {
Nprogress.done();
return importComponent();
})
}
// dashboard components
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
component: Full,
redirect: '/dashboard/dashboard-v1',
children: [
{
path: '/dashboard/dashboard-v1',
component: asyncComponent(() => import('../views/dashboard/DashboardOne')),
meta: {
title: 'Dashboard V1',
breadcrumb: 'Dashboard / Dashboard V1'
}
},
{
path: '/dashboard/dashboard-v2',
component: asyncComponent(() => import('../views/dashboard/DashboardTwo')),
meta: {
title: 'Dashboard V2',
breadcrumb: 'Dashboard / Dashboard V2'
}
}
]
},
{
path: '/session/sign-up',
component: asyncComponent(() => import('../views/SignUp')),
meta: {
title: 'Sign Up',
breadcrumb: 'Session / Sign Up'
}
},
{
path: '/session/login',
component: asyncComponent(() => import('../views/Login')),
meta: {
title: 'Login',
breadcrumb: 'Session / Login'
}
},
{
path: '/session/lock-screen',
component: asyncComponent(() => import('../views/LockScreen')),
meta: {
title: 'Lock Screen',
breadcrumb: 'Session / Lock Screen'
}
}
]
})
router.beforeResolve((to, from, next) => {
// If this isn't an initial page load.
if (to.name) {
// Start the route progress bar.
NProgress.start()
}
next()
})
router.afterEach((to, from) => {
// Complete the animation of the route progress bar.
NProgress.done()
})
export default router;
with this, you would have the loader on each route change.