vue js how to validate the particular routes for the particular roles - vuejs2

In my application User wants the ability to create a role from the interface, and assign the pages to the role. Which Means both roles and routes are dynamic.
Here in the example the routes to the roles are defined in the client. Where we have to assume that the user must be in the certain roles to be allowed to access that page. But I don't know which role needs to be assigned to that pages?
Currently what I know is that we can check the whether the user is authenticated or not before accessing the page, but I am obstructing in the logic to check whether the pages are not accessible to the user with the particular roles.
As i know that i can validate the routes logic using
router.beforeEach((to, from, next) => {
//how to validate
})
Currently, my pages look like below
items: [
{
name: 'Dashboard',
url: '/dashboard',
icon: 'icon-speedometer'
},
{
name: 'Base',
url: '/base',
icon: 'icon-puzzle',
children: [
{
name: 'Cards',
url: '/base/cards',
icon: 'icon-puzzle'
},
{
name: 'Forms',
url: '/base/forms',
icon: 'icon-puzzle'
}
]
}
]
I also have other information on the client side.
DisplayPicture
FullName
Role
RoleHierarchy
RoleId
UserId
Can you guide me to the logic on how to verify whether the pages are accessible to the roles or not?

This is the code I am using to check whether the page is accessible to current user or not.
router.beforeEach((to, from, next) => {
// Permission based routing
if (to.matched.some(record => record.meta.conditionalRoute)) {
if (to.name === 'Administration') {
if (hasRole('Admin')) {
next()
}
}
next(false)
} else {
next()
}
})
In above example if name of the to.name is "Administration" then check if current user's role is "Admin" or redirect him back to previous page.
You also need to add meta: {conditionalRoute: true} to your routes where you need to apply conditional routing.

Related

Vue getter in beforeEnter returns undefined after page reloads

I have login page and then if user logs in, there is user page. But when I reload user page, It shows false in the console even though user didnt logged out. For login I'm setting token in local storage. What should I do differently, why the code doesnt work? Thanks
This is my route
{
path: '/userpage',
name: 'User Page',
beforeEnter: async (to, from, next) => {
if (await store.getters.isLoggedIn == false) {
console.log(false)
next({ name: 'Login' })
} else {
console.log(true)
next()
}
},
component: UserPage,
},
Use localstorage for storing login data so you can preserve it after reload

Vue.js Routing shows 404 error message briefly before redirect after auth check

I have followed a number of posts' guidance on Stack Overflow and other websites about setting up Vue routes to check for user authentication. The setup I now have does essentially work correctly (for each route, the user authentication status is checked, and redirected to the login page if necessary) but there is a small issue in that just before the user is redirected, the standard Nuxt/Vue 404 page screen flashes up momentarily.
This is an example of each route that requires user authentication that I have in router.js:
...
{
path: '/question/:id/comments',
name: 'comments',
component: page('Comments.vue'),
meta: {requiresAuth: true},
beforeEnter: (to, from, next) => {
guard(to, from, next);
}
},
...
And here is my guard() function that checks the user authentication and then redirects them with next() as required:
const guard = function(to, from, next) {
axios.get(process.env.apiUrl + 'check-auth').then(response => {
if( to.matched.some( record => record.meta.requiresAdmin ) ) {
if( response.data.is_moderator !== 1 ) {
next({ path: '/' });
} else {
next();
}
} else if( to.matched.some( record => record.meta.requiresAuth ) ) {
if( !response.data.id ) {
next({
path: '/login',
params: { nextUrl: to.fullPath }
});
} else {
next();
}
} else {
next();
}
});
};
Many articles online suggested using localStorage to check the user authentication but this doesn't work in router.js (presumably because its server side and not client side) but I got around this using a Laravel API call with Axios to check it instead.
If anyone can shed any light on why the 404 screen flashes up first before the redirect? Going to the routes directly works fine, so I am guessing it must be something to do with the next() method.

Wait for state update in vuejs router´s beforeEnter

I want to restrict access to certain pages in my vue router. Instead of having the auth logic in each component, I would prefer, for instance, to just have a 'hasUserAccess' check in my child-routes where it´s needed
{
path: 'admin',
name: 'admin',
beforeEnter: hasUserAccess,
component: () => import(/* webpackChunkName: "admin" */ '#/_ui/admin/Admin.vue')
},
...
function hasUserAccess(to, from, next) {
if (myState.user.isAdmin) {
next();
} else {
next({ path: '/noaccess' });
}
}
This works as intended when navigating from another page to the 'admin' page. This does not work when i manually type the /admin url (or pressing f5 while on the admin page) because the user object hasn´t been fetched from the server yet (some other logic is taking care of fetching the user).
The 'beforeEnter' is async, but as far as I know it ain´t possible to 'watch' the user object, or await it, from the router since the router is not a typical vue component.
So how is this common problem normally solved?
Just apply the beforeEach to the router itself. On the router file, you could do this:
router.beforeEach((to, from, next) => {
//in case you need to add more public pages like blog, about, etc
const publicPages = ["/login"];
//check if the "to" path is a public page or not
const authRequired = !publicPages.includes(to.path);
//If the page is auth protected and hasUserAccess is false
if (authRequired && !hasUserAccess) {
//return the user to the login to force the user to login
return next("/login");
}
//The conditional is false, then send the user to the right place
return next();
});
Try to modify this at your convenience, but this is more or less what I do in a situation like yours.

How do I automatically redirect the user if they are already logged in using Vue and Firebase authentication?

Description
I am trying to automatically route the user to the "Games.vue" component if they are already logged in. For authentication I am using Firebase and I check if they are logged in using:
var user = firebase.auth().currentUser;
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
What I want to have happen is for the user to not see the Login page if they are already signed in. So they are taken directly to the Games page. I don't know how to accomplish this using Vue. I need something to run before the Login-component that redirects if logged in.
Attempt at solution
The only way I know how to solve this is to show the Login page, check if the Firebase user is logged in and then go to the Games page. This can work, but it isn't the behavior I am looking for. I am using the Vue router. Thank you for your help.
I would suggest to use a VueRouter global guard like so:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
if (!user) {
next('login');
} else {
next();
}
})
That being said, you then need a way to specify which route requires authentication. I would suggest to use route meta fields like so:
routes = [
{
name: 'login',
path: '/login',
meta: {
requiresAuth: false
}
},
{
name: 'games',
path: '/games',
meta: {
requiresAuth: true
}
}
]
Now your guards becomes:
if (!user && to.meta.requiresAuth) {
next('login');
} else {
next();
}
Vue router provides an example for this use case, take a look at the documentation.
TIP: Make sure to subscribe to auth changes using Firebase onAuthStateChanged method.
let user = firebase.auth().currentUser;
firebase.auth().onAuthStateChanged(function(user) {
user = user;
});
EDIT: To redirect once logged in, just watch for auth changes and redirect using router.push.
auth.onAuthStateChanged(newUserState => {
user = newUserState;
if (user) {
router.push("/games");
}
});

Restrict routing per role

Is it possible to restrict certain routes and / or change components for any route base on a value such as the logged in user's role?
I want this so an administrator's default page is different to a normal user, but also perhaps to restrict access if the route is set manually in the browser.
Or is it a better solution to have a base component that redirects to another route?
I understand that restricting access via the router does not replace real account security, but would seem like a first good step in preventing users guessing restricted routes.
Here is a great example of implementing authentication and authorization with vue router: https://scotch.io/tutorials/vue-authentication-and-route-handling-using-vue-router
Basically you can check premissions before letting user open the protected component. The easiest way to achieve this is using router guards. In your router definitions:
{
path: '/proctected',
beforeEnter(to, from, next) {
if (isAuthenticated()) {
if (!hasPermissionsNeeded(to)) {
next('/page-to-show-for-no-permission');
} else {
next();
}
} else {
next('/page-to-show-for-unauthenticated-users');
}
}
}
This guard will protect from entering /proctected url. Here you can check the working codepen: https://codepen.io/anon/pen/JwxoMe
Below an example of guard for all routes:
router.beforeEach((to, from, next) => {
if (isAuthenticated()) {
if (!hasPermissionsNeeded(to)) {
next('/page-to-show-for-no-permission');
} else {
next();
}
} else {
next('/page-to-show-for-unauthenticated-users');
}
})
More about router guards: https://router.vuejs.org/guide/advanced/navigation-guards.html#per-route-guard