problem in redirecting in guarded route - Vue js Router - vue.js

I have this route in my vue router.js file .
routes: [{
path: "/",
component: Home,
beforeEnter: (to, from, next) => {
if (!store.state.is_login) {
next('/login')
}
next()
}
}]
I use beforeEnter option for redirecting user if store.state.is_login === true
first problem :
so when I enter the url in browser I will redirect to /login page. this is works fine. but when I click the logo button, this beforeEnter function is not working.
this is my button that uses :
<router-link to="/" class="bp-logo"><Logo />home</router-link>
the second problem is :
is_login is in my store.state.is_login
I am storing my token in the localStorage
user_info is in store.state.user
problem :
condition 1: if !is_login redirect to /login .
condition 2 : if token exists and !is_login => request to backend /user with token and get user_info and set is_login true.
condition 3 : if !is_login && !token redirect to /login

You need to change your beforeEnter method to access the store instance. Rewrite like this:
beforeEnter: (to, from, next) => {
if (!this.$store.state.is_login) {
next('/login')
}
next()
}

I figured it out somehow. the first problem was when you render a route .then you are click for getting to that route again the function router.beforeEach not trigger. so I find another method in documentation.
routes: [{
path: "/",
component: Home,
beforeEnter: isAuthenticated,
}]
and this is my custom function for handling both problems .
const isAuthenticated = (to, from, next) => {
if (!store.state.is_login) {
if ((localStorage.getItem('token')) && (lodash.isEmpty(store.state.user))) {
let headers = {
headers: {
Authorization: localStorage.getItem("token"),
"Access-Control-Allow-Origin": "*"
}
};
axios
.get(`${store.state.api}admin/user`, headers)
.then(response => {
store.state.user = response.data.user;
store.state.is_login = true;
next("/");
})
.catch(error => {
store.state.Error = error;
next('/login')
});
}
next('/login')
return
}
next()
return
}

Related

vue router route guard check vuex state

I have a route guard that looks like this. It checks the vuex store for a property, which is fetched async on page load. Since the code runs before the property is set, it always resolves as false.
Any ideas for a work around or a proper implementation?
router.beforeEach(async (to, from, next) => {
if (to.matched.some(record => record.meta.requiresActivated)) {
if (store.state.account.post_title !== 'true') {
next({
path: '/activate',
query: { redirect: to.fullPath, id: store.state.user.id }
})
}
next()
} else {
next()
}
})

How to restrict going back to login page after logged in in vue?

I want restrict users from going to back to login page after he/she logs in. How to do this using guard in routes ?
My code :
guard.js
export default function guard(to, from, next) {
const token = localStorage.getItem('_utoken');
if (token) {
next();
} else {
next('/login');
}
}
and in routes.js I used beforeEnter:guard inside every object except login route object like this
{
path:'/home,
name: 'Home,
component: Home,
beforeEnter: guard,
}
If token exists restrict from going to login page or signup page .
Instead of adding guard into each and every route, you can add a global guard to all routes:
router.beforeEach((to, from, next) =>
{
const token = localStorage.getItem('_utoken');
if (!to.meta.public)
{
// page requires authentication - if there is none, redirect to /login
if (token) next();
else next('/login');
}
else
{
// Login is supposedly public - skip navigation if we have a token
if (token ? to.path !== '/login' : true) next();
}
});
{
path: '/home',
name: 'Home,
component: Home,
},
{
path: '/login',
name: 'Login',
component: Login,
meta:
{
public: true
}
}

vue router always takes me back to login

I'd like to use a route guard to check localstorage if the user has the rights to login or not (simple boolean true or false for testing).
If I log in, the router always takes me back to my login, even if the localstoreage says it's authenticated.
If I then click on my logo (/), I come to the user area and all works fine.
Router.beforeEach((to, from, next) => {
const isAuthed = JSON.parse(localStorage.getItem("store"));
if (to.path !== "/login" && isAuthed === null) {
next("/login");
} else if (to.path !== "/login" && isAuthed.auth === false) {
next("/login");
} else {
next();
}
});
These are my routes:
const routes = [
{ path: "", name: "Home", component: () => import("pages/Home") },
{ path: "/login", name: "Login", component: () => import("pages/Login") },
{ path: "*", component: () => import("pages/Error404.vue") },
];
export default routes
This is my login function to toggle true/false on login and then push the user to home:
login: function () {
store.auth = true
this.$router.push('/')
}
What am I thinking wrong here?
I thought because on the first visit, localstorage is null because it will be set after login, so I added a check if object is null but it's the same.
thanks

Why does my Vue Router throw a Maximum call stack error?

I have a really simple routing practically looks like this I'm using this under electron
import Vue from "vue";
import VueRouter from "vue-router";
import Projects from "../views/Projects.vue";
import RegisterUser from "#/views/RegisterUser.vue";
//import { appHasOwner } from "#/services/";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "projects",
component: Projects,
meta: {
requiresUser: true
}
},
{
path: "/register",
name: "register",
component: RegisterUser
},
{
path: "/settings",
name: "settings",
meta: {
requiresUser: true
},
// 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/Settings.vue")
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
router.beforeEach((to, from, next) => {
if (to.matched.some(route => route.meta.requiresUser === true)) {
//this will be for test case undefined
let user;
if (typeof user === "undefined") {
// eslint-disable-next-line no-console
console.log(user); //logs undefined but at the end no redirect
next("/register");
} else {
next();
}
}
});
export default router;
taking the example from the docs
// GOOD
router.beforeEach((to, from, next) => {
if (!isAuthenticated) next('/login')
else next()
})
the application can boot only if there is a user attached in database either should redirect to the register component but the code above will end with Maximum call stack size exceeded. So how to check with beforeEach conditions end redirect to a given page?
The Maximum call stack size exceeded is usually due to infinite recursion, and that certainly seems to be the case here. In router.beforeEach you're calling next to go to the /register route, which goes back into this method, which calls next, and so on. I see you have a requiresUser in your meta, so you need to check that in beforeEach, like this:
router.beforeEach((to, from, next) => {
// If the route's meta.requiresUser is true, make sure we have a user, otherwise redirect to /register
if (to.matched.some(route => route.meta.requiresUser === true)) {
if (typeof user == "undefined") {
next({ path: '/register' })
} else {
next()
}
}
// Route doesn't require a user, so go ahead
next()
}

vuejs - Redirect from login/register to home if already loggedin, Redirect from other pages to login if not loggedin in vue-router

I want to redirect user to home page if logged-in and wants to access login/register page and redirect user to login page if not logged-in and wants to access other pages. Some pages are excluded that means there is no need to be logged in so my code is right below:
router.beforeEach((to, from, next) => {
if(
to.name == 'About' ||
to.name == 'ContactUs' ||
to.name == 'Terms'
)
{
next();
}
else
{
axios.get('/already-loggedin')
.then(response => {
// response.data is true or false
if(response.data)
{
if(to.name == 'Login' || to.name == 'Register')
{
next({name: 'Home'});
}
else
{
next();
}
}
else
{
next({name: 'Login'});
}
})
.catch(error => {
// console.log(error);
});
}
});
But the problem is that it gets into an infinite loop and for example each time login page loads and user not logged-in, it redirects user to login page and again to login page and...
How can I fix this?
Here's what I'm doing. First I'm using a meta data for the routes, so I don't need to manually put all routes that are not requiring login:
routes: [
{
name: 'About' // + path, component, etc
},
{
name: 'Dashboard', // + path, component, etc
meta: {
requiresAuth: true
}
}
]
Then, I have a global guard like this:
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.isLoggedIn) {
next({ name: 'Login' })
} else {
next() // go to wherever I'm going
}
} else {
next() // does not require auth, make sure to always call next()!
}
})
Here I am storing if the user is logged in or not, and not making a new request.
In your example, you have forgotten to include Login into the list of pages that "don't need authentication". So if the user is trying to go to let's say Dashboard, you make the request, turns out he's not logged in. Then he goes to Login, BUT your code checks, sees it's not part of the 3 "auth not required" list, and makes another call :)
Therefore skipping this "list" is crucial! ;)
Good luck!
If someone is still looking for an answer, you can reverse the logic. So, the same way you have requiresAuth, you will have hidden routes for authenticated users. (example with firebase)
routes: [{
path: '/',
redirect: '/login',
meta: {
hideForAuth: true
}
},
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
meta: {
requiresAuth: true
}
}]
And in your beforeEeach
router.beforeEach((to, from, next) => {
firebase.auth().onAuthStateChanged(function(user) {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!user) {
next({ path: '/login' });
} else {
next();
}
} else {
next();
}
if (to.matched.some(record => record.meta.hideForAuth)) {
if (user) {
next({ path: '/dashboard' });
} else {
next();
}
} else {
next();
}
});
});
Derived from the answer #Andrey Popov provided.
I prefer to explicitly disallow a route that doesn't require auth. This prevents accidentally not protecting your routes, i.e. the default case is to redirect to a login page
router.beforeEach((to, from, next) => {
if (to.name === 'login') {
next() // login route is always okay (we could use the requires auth flag below). prevent a redirect loop
} else if (to.meta && to.meta.requiresAuth === false) {
next() // requires auth is explicitly set to false
} else if (store.getters.isLoggedIn) {
next() // i'm logged in. carry on
} else {
next({ name: 'login' }) // always put your redirect as the default case
}
})
In addition to the Andrey's answer, if you use firebase authentication, need to add onAuthStateChanged around createApp in main.ts.
firebase.auth().onAuthStateChanged((user) => {
createApp(App).use(store).use(router).mount('#app')
})
This is very basic concept for this, use redirect:'/dashboard' this way you can do. you have to define it in your route list. like this way. you can ignore mate: {}. i used this for different purpose.
routes: [ ....
{
path: '/login',
name: 'login',
component: LoginView,
meta:{needAuth:false},
redirect:'/dashboard'
},
{
path: '/sign-up',
name: 'sign-up',
component: SignUpView,
meta:{needAuth:false},
redirect:'/dashboard'
},
{
path: '/dashboard',
name: 'dashboard',
component: UserDashboard,
meta:{needAuth:true},
beforeEnter: ifAuthenticated,
}
]
function ifAuthenticated (to, from, next) { store.test();
if (localStorage.getItem("login-token")) { console.log("login done");
next();
return;
}
router.push({ name: 'login' });
};
// requireAuth for those you want to authenticate
// onlyGuest for those you don't want to autenticate to open other thing if already
// logged in then it's redirect to home
router.beforeEach((to,from,next)=>{
if(to.matched.some(record => record.meta.requireAuth)){
if(!store.state.loginUser){
next({name:'Login'});
}
else{
next();
}
}
else if (to.matched.some(record => record.meta.onlyGuest)) {
if (store.state.loginUser && store.state.loginUser.token) {
next({name: "Home"});
} else {
next();
}
}
else{
next();
}
});