I am very beginner in JS and VUE. I make mini CMS in Vue and Laravel. I create this router in Vue:
import Vue from 'vue'
import Router from 'vue-router'
// Containers
const TheContainer = () => import('@/containers/TheContainer')
// Views
const Dashboard = () => import('@/views/Dashboard')
....
Vue.use(Router)
let router = new Router({
mode: 'hash', // https://router.vuejs.org/api/#mode
linkActiveClass: 'active',
scrollBehavior: () => ({ y: 0 }),
routes: configRoutes()
})
router.beforeEach((to, from, next) => {
let roles = localStorage.getItem("roles");
if(roles != null){
roles = roles.split(',')
}
if(to.matched.some(record => record.meta.requiresAdmin)) {
if(roles != null && roles.indexOf('admin') >= 0 ){
next()
}else{
next({
path: '/login',
params: { nextUrl: to.fullPath }
})
}
}else if(to.matched.some(record => record.meta.requiresUser)) {
if(roles != null && roles.indexOf('user') >= 0 ){
next()
}else{
next({
path: '/login',
params: { nextUrl: to.fullPath }
})
}
}else{
next()
}
})
export default router
function configRoutes () {
return [
{
path: '/',
redirect: '/dashboard',
name: 'Home',
component: TheContainer,
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: Dashboard
},
]
},
]
}
It's work fine, but I have 2 problems:
- When user is not login - then I need redirect to my login page (/login) - not to /dashboard
- When user session was expired - then redirect to login page
If user is login - then first page (and main page) is /dashboard
How can I make it?
Please help me.
CodePudding user response:
What do you think of this:
import Vue from 'vue'
import Router from 'vue-router'
// Containers
const TheContainer = () => import('@/containers/TheContainer')
// Views
const Dashboard = () => import('@/views/Dashboard')
// ....
Vue.use(Router)
let router = new Router({
mode: 'hash', // https://router.vuejs.org/api/#mode
linkActiveClass: 'active',
scrollBehavior: () => ({ y: 0 }),
routes: configRoutes()
})
// routing logic for not-logged-in
// users with a role
const useToLoginObj = (to) => ({
path: '/login',
params: {
nextUrl: to.fullPath
}
})
// DON'T DO THIS IN PRODUCTION!
// secure/security info should
// **NEVER** BE SAVED TO LOCALSTORAGE!!!!!
const fetchUserRoles = () => {
const roles = localStorage.getItem("roles")?.split(',')
return roles
}
// possible roles as keys
// corresponding required meta as value
const rolesDict = {
admin: 'requiresAdmin',
user: 'requiresUser',
}
const getRequiredRole = ({ to, rolesDict }) => {
let requiredRole = null
for (let key in roles) {
// if the required role is already set, then
// don't do anything
if (!requiredRole && to.matched.some(record => record.meta[rolesDict[key]])) {
requiredRole = key
}
}
// if no role is required, then the
// return value is null (falsy)
return requiredRole
}
// if fetched roles include the requiredRole
const routeAuthUser = ({ roles, requiredRole, toLogin, next }) => {
if (!roles.includes(requiredRole)) {
next(toLogin)
} else {
next()
}
}
router.beforeEach((to, from, next) => {
const requiredRole = getRequiredRole({to, rolesDict})
// if requiredRole is falsy (this route
// doesn't require a role), then go
if (!requiredRole) {
next()
} else {
const roles = fetchUserRoles()
const toLogin = useToLoginObj(to)
// if no roles are there, then go to login
if (!roles || !roles.length) {
next(toLogin)
} else {
// user is routed based on her/his role
routeAuthUser({ roles, requiredRole, toLogin, next })
}
}
})
More verbose than the code in question, but
- steps are broken up, so the logic shines through better
- the order of
beforeEachrouting steps is more logical ("error first" approach)
I could not try it out, so there might be errors in the code, but the logic (I think) is clear: break it up to small pieces then construct the logic you want from those small pieces.
SUGGESTION
Try to find a different solution for storing user roles. localStorage is the least safe (even calling it "the least safe" is an exaggeration) solution for secure data.
