Problem when I want to access a component from an external link vue router - 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

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.

Redirect from beforeEnter causes infitite cycle and does not redirect

I have a problem with the nonworking redirect. I check is the user is logged in and the info is right, but when it comes to redirecting it does not redirect and just goes in this beforeEnter over and over again. Can somebody say what am I doing wrong?
I am presenting here my RouteConfig and the problem with the first beforeEnter.
export const routes: RouteConfig[] = [
{ path: '*', redirect: '/' },
{
path: '/',
component: router_view,
async beforeEnter(to, from, next) {
var hasPermission = await storage.get('state').user.tokens.access;
console.log(!!hasPermission)
if (!!hasPermission && from.fullPath.startsWith('/')) {
return next('profile');
} else {
return next()
}
},
children: [
{
name: 'landing',
meta: { requiresAuth: false },
path: '',
component: require('pages/index').default
},
{
meta: { requiresAuth: true },
path: 'seller',
component: require('pages/seller').default,
children: [
{
path: '',
name: 'profile',
redirect: 'profile'
},
{
path: 'account',
component: require('pages/seller/account').default
},
{
path: 'help/:url?',
component: require('pages/seller/help').default
},
{
path: 'profile',
component: require('pages/seller/profile').default
},
{
path: 'finances/:shop?',
name: 'finances',
props: route => ({
...route.query,
...route.params
}),
component: require('pages/seller/finances').default
},
{
path: 'shop',
component: require('pages/seller/shop').default,
children: [
{
path: '',
redirect: 'main'
},
{
path: 'main',
component: require('pages/seller/shop/main').default
},
// {
// path: 'rating',
// component: require('pages/seller/shop/rating').default
// },
{
path: 'design',
component: require('pages/seller/shop/design').default
},
]
},
{
path: 'invoices',
redirect: { name: 'invoices-send' },
component: require('pages/seller/invoices/index').default,
children: [
{
path: 'send',
name: 'invoices-send',
component: require('pages/seller/invoices/send').default,
},
{
path: 'return',
name: 'invoices-return',
component: require('pages/seller/invoices/return').default
},
{
path: 'create-send',
component: require('pages/seller/invoices/createInvoice').default,
},
{
path: 'create-return',
component: require('pages/seller/invoices/createInvoice').default,
},
]
},
{
path: 'products',
component: router_view,
children: [
{
path: '',
redirect: 'all'
},
{
path: 'new',
component: require('pages/seller/products/new').default,
children: [
{
path: '',
component: require('pages/seller/products/new/createproduct').default
},
]
},
{
path: 'id/:productid/edit',
component: require('pages/seller/products/new').default,
children: [
{
path: '',
name: 'edit-product',
props: route => ({ ...route.params, ...route.query }),
component: require('pages/seller/products/new/createproduct').default
},
{
path: 'sku',
name: 'edit-product-sku',
component: require('pages/seller/products/new/createsku').default,
},
]
},
{
path: 'invoices',
redirect: { name: 'invoices-send' }
},
{
path: 'id/:productid',
component: require('pages/seller/products/_productid').default,
children: [
{
path: 'main',
name: 'product-page-solo',
component: require('pages/seller/products/_productid/main').default
},
// {
// path: 'reviews',
// component: require('pages/seller/products/_productid/reviews').default
// },
// {
// path: 'statistics',
// component: require('pages/seller/products/_productid/statistics').default
// },
{
path: 'printlabels',
name: 'product-labels-solo',
component: require('pages/seller/products/_productid/printlabels').default
},
]
},
{
path: 'stickers',
name: 'products-stickers',
component: require('pages/seller/products/stickers').default,
},
{
path: ':table',
name: 'product-list',
component: require('pages/seller/products/index').default,
props: _ => ({
tabletype: _.params.table
}),
beforeEnter(to, from, next) {
if (to.params.table === 'invoices') {
return next({ name: 'invoices' });
} else {
next();
}
},
children: [
{
path: 'id/:productid',
component: require('pages/seller/products/_productid').default,
children: [
{
path: 'main',
name: 'product-page',
component: require('pages/seller/products/_productid/main').default
},
// {
// path: 'reviews',
// component: require('pages/seller/products/_productid/reviews').default
// },
// {
// path: 'statistics',
// component: require('pages/seller/products/_productid/statistics').default
// },
{
path: 'printlabels',
name: 'product-labels',
component: require('pages/seller/products/_productid/printlabels').default
},
]
},
]
}
]
}
]
},
{
meta: { requiresAuth: false },
name: 'signin',
path: '/signin',
component: router_view,
children: [
{
path: '',
name: 'signin',
component: require('pages/signin/index').default
},
{
path: 'restore',
component: router_view,
children: [
{
path: '',
component: require('pages/signin/restore/index').default
},
{
path: 'password',
component: require('pages/signin/restore/newpassword').default,
beforeEnter(to, from, next) {
if (from.fullPath.startsWith('/confirm'))
return next();
else
return next('/');
}
}
]
}
]
},
{
path: 'confirm',
meta: { requiresAuth: false },
component: require('pages/confirm/index').default,
beforeEnter(to, from, next) {
const path = from.fullPath ? from.fullPath : from.path;
if (path === '/signin' || path === '/signup' || path === '/signin/' || path === '/signup/' || path === '/' || path === '/signin/restore' || path === '/signin/restore/'
|| (from.path.startsWith('/confirm') && from.query === to.query)
|| to.query.from === 'account'|| to.query.from === 'restore')
return next();
else
return next('/');
}
},
{
name: 'signup',
path: 'signup',
meta: { requiresAuth: false },
component: router_view,
children: [
{
path: '',
name: 'signup',
component: require('pages/signup/index').default
},
{
path: 'social',
component: require('pages/signup/social').default
},
]
},
{
meta: { requiresAuth: false },
path: 'terms-of-use',
component: require('pages/terms-of-use').default
}
]
}
];

Why does the router link not work the first time?

I have a grpc application, there is authorization. When you start a project, you must be logged in. I decided to add under the login button if you are not registered. But the router does not work. Only at the entrance, go to the registration page. Please help to understand what is the mistake? Why is seemingly blocked?
routes.js
const routes = [
{
path: "/",
component: () => import("layouts/MainLayout"),
children: [
{
path: "",
component: () => import("pages/Index"),
meta: { requireAuth: true }
},
{
path: "/logs",
component: () => import("pages/Logs"),
meta: { requireAuth: true, admin: true }
}
]
},
{
path: "/",
component: () => import("layouts/AuthLayout"),
children: [
{
path: "/welcome",
component: () => import("pages/Auth"),
meta: { guest: true }
},
{
path: "/register",
component: () => import("pages/Register"),
meta: { guest: true }
}
]
}
];
I tried many things, like in Auth.vue:
<q-item to='/register'>Sign Up</q-item>
<router-link tag="a" :to="{path:'/register'}" replace>Go</router-link>
<span #click="callSomeFunc()">Register</span>
...
methods: {
callSomeFunc() {
this.$router.push({ path: "/register" });
}
My router-view in App.vue
for more information github repo
You have duplicate routes in your config - the path / is used on 2 routes. You should fix this.
To prevent unauthorized users to see your protected pages you can add a global navigation guard to your router through the beforeEach hook:
import VueRouter from 'vue-router';
const routes = [
{
path: "/",
component: () => import("layouts/MainLayout"),
meta: { requireAuth: true },
children: [
{
path: "",
component: () => import("pages/Index"),
},
{
path: "logs",
component: () => import("pages/Logs"),
meta: { admin: true }
}
]
},
{
path: "/login",
component: () => import("layouts/AuthLayout"),
children: [
{
path: "",
component: () => import("pages/Auth"),
},
{
path: "/register",
component: () => import("pages/Register"),
}
]
}
];
const router = new VueRouter({
routes
});
router.beforeEach((to, from, next) =>
{
if (to.matched.some(route => route.meta.requireAuth))
{
if (userNotLogged) next('/login');
else next();
}
else next();
});
export default router;
You may also consider reading a more verbose tutorial, e.g. https://www.digitalocean.com/community/tutorials/how-to-set-up-vue-js-authentication-and-route-handling-using-vue-router

Accessing authenticated route with vue-router

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

Middleware for routes in vue

I want to deny some routes for authorized users, like login page, register page, but I don't know how to make those middlewares
Routes
routes: [
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/register',
name: 'Register',
component: Register
}
]
Function that I use in components
computed: {
isLoggedIn () {
return this.$store.getters.isLoggedIn
}
}
In your router you can do something like this.
All routes marked with meta: { requiresLogin: true} } will be checked in the BeforeEach method. Here we redirect them to the login page.
You can in principle halt the router and show a modal or whatever you like here.
Router
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from '../views/App.vue'
import Login from '../views/login.vue'
import Register from '../views/registser.vue'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/', name: 'app', component: App, meta: { requiresLogin: true} },
{ path: '/login', name: 'login', component: Login },
{ path: '/register', name: 'register', component: Register },
]
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresLogin)) {
if (**USER IS NOT LOGGED IN**) {
next({
path: '/login',
query: {
redirect: to.fullPath,
},
});
} else {
next();
}
} else {
next();
}
})
export default router
Create additional meta field requiresAuth in your routes to specify which route require logged user:
routes: [{
path: '/',
name: 'Dashboard',
component: Dashboard,
children: [{
path: 'settings',
name: 'Settings',
component: Settings,
meta: {
requiresAuth: true
}
}],
meta: {
requiresAuth: true
}
},
{
path: '/login',
name: 'Login',
component: Login
}
],
Then add middleware in main.js:
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
const authUser = JSON.parse(window.localStorage.getItem('authUser')) // your oauth key
if (authUser && authUser.access_token) {
next()
} else {
next({
name: 'Login'
})
}
}
next()
})
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: {
App
}
})