在类似于后台管理项目中我们一般是需要做权限分割以及页面访问权限设置的,在这里我和大家一起分享下这类项目的思路以及为大家提供一个简单的项目模板.
在权限分割以及页面权限方面的实现根据需求的不同可以大致分为两类:(1)用户的权限信息固定,每个角色访问的页面都是固定的;(2)用户的权限信息不固定,每个角色能够访问的页面是由超级管理员设定的.这两类需求在某些方面是有这共同点的,比如都是需要动态路由的添加,需要前端去挑选动态路由,控制页面跳转的规则等,针对于这两类我们可以采取不同的思路去解决(使用vue框架).
1.第一类的解决方案.
思路:由于角色对页面的访问权限是固定的(不需要做到可随时更改),所以我们完全可以将权限信息由前端去控制,后台只需要将角色交给前端,由前端去挑选该角色可访问的所有页面的路由配置,并将筛选出来的路由加载到项目中.
实现方法:在上面我们提到这一类的权限信息可以由我们前端去控制,但是怎么去控制?路由的由两个数组控制,设置一个不包含权限相关的路由数组,同时设置一个有关权限的所有页面路由的路由数组,在这个路由上我们可以将权限信息直接绑定到路由设置上,具体实现如下:
var asynchronousRouter=[{
path: '/',
name: 'about',
redirect: '/home',
component: layout,
children: [{
path: 'home',
name: "questionsList",
rules:["admin","user1"],
component: () => import('@/views/questions/questionsList.vue')
},
{
path: 'addQuestion',
name: "addQuestion",
rules:["admin"],
component: () => import('@/views/questions/addQuestion.vue')
},
{
path: 'addOptions',
name: "addOptions",
rules:["admin","user1",],
component: () => import('@/views/questions/addOptions.vue')
}]}
]
由上面的代码我们可以看到在路由配置中我们添加了rules字段来标识页面权限,在登陆时我们获取到后台给我们的权限信息(即权限角色为admin还是user1),然后我们在异步路由(asynchronousRouter)的数组中根据rules字段去筛选符合的路由信息,这样我们就能拿到该角色能访问的所有页面的url.具体的详细操作在下面详细讲解.
第二类的解决方案:
/*
动态获取路由的方法
*/
import {
dynamicRouter,
allNo
} from './index'
export function getRouter(userSetMenu) {
var arr = []
dynamicRouter.forEach((item) => {
if (item.children) {
userSetMenu.find((e, index) => {
let newArr = {
path: item.path,
name: item.name,
component: item.component,
children: []
};
arr.push(newArr)
item.children.forEach(child => {
if (userSetMenu[index].children) {
userSetMenu[index].children.find(userItem => {
userItem.path == child.path ? arr[arr.length ? arr.length - 1 : arr.length].children.push(child) : arr = arr;
})
}
})
})
} else {
userSetMenu.find(e => {
e.path == item.path ? arr.push(item) : arr = arr;
})
}
});
arr.push(allNo)
return arr;
}
思路:由于每一个角色的权限信息不固定,可以超级管理员设定,所以前端无法保存每个角色的权限信息,只能由后台存储权限信息以及路由信息.在登陆时后台返回权限
以及路由信息,然后有前端控制页面的加载逻辑.
实现方法:由于角色的权限信息可以由超级管理员设定,所以每个角色能访问的页面时不确定的,所以不能像上面那样加一个权限字段解决叶哥问题.有一点相似的是,同样设置基本路由,一个权限相关的路由数组,在登陆成功后获取后端传递的权限信息,挑选符合条件的路由,再由addRouter方法挂载路由即可;具体实现的代码如下:
(1)前端控制页面跳转的逻辑(路由钩子函数)
router.beforeEach((to, from, next) => {
console.log("路由钩子开始==>")
if (sessionStorage.token) { //判断是否含有权限字段(是否登陆过)
if (sessionStorage.router) { //判断后台是否返回权限路由
console.log(to.path)
var nextPath = to
console.log("已加载路由和token信息" + to.path)
if (to.path == '/') { //满足以上两个条件时打开网站,直接进入首页
next("/home")
} else {
console.log("正常跳转")
next()
}
} else {
let newRouter = getRouter(JSON.parse(sessionStorage.menu))
sessionStorage.router = JSON.stringify(newRouter)
router.options.routes = router.options.routes.concat(newRouter)
router.addRoutes(newRouter) // 动态添加可访问路由表
next({
...to,
replace: true
})
console.log(router.options.routes)
}
} else {
if (whiteList.indexOf(to.path) != '-1') {
console.log(whiteList.indexOf(to.path))
next()
} else {
next('/')
}
}
})
在这里权限信息的存储我是用的是sessionStorage去保存的,但是这样也会引起一些问题(刷新后addrouter添加的动态路由会失效),具体解决方法为在App.vue文件中执行以下addRouter方法.同时要记住不要直接使用存储在ssessionStorage中的路由表(路由表在存储时,我们进行了格式处理,这样处理后存储下来的就不是正确的路由信息了);但是又vuex存储时就不会有这样的问题,但是由于刷新会导致vue的重新实例化,所有的数据都会再次加载(包含获取权限信息),与本地存储相比http请求要增加.不管时哪一种方式去存储权限信息都是各有利弊的,具体怎么实现需要个人以及项目的需求来决定.
至于路由挑选的逻辑代码,如下:
/*
动态获取路由的方法
*/
import {
dynamicRouter,
allNo
} from './index'
export function getRouter(userSetMenu) {
var arr = []
dynamicRouter.forEach((item) => {
if (item.children) {
userSetMenu.find((e, index) => {
let newArr = {
path: item.path,
name: item.name,
component: item.component,
children: []
};
arr.push(newArr)
item.children.forEach(child => {
if (userSetMenu[index].children) {
userSetMenu[index].children.find(userItem => {
userItem.path == child.path ? arr[arr.length ? arr.length - 1 : arr.length].children.push(child) : arr = arr;
})
}
})
})
} else {
userSetMenu.find(e => {
e.path == item.path ? arr.push(item) : arr = arr;
})
}
});
arr.push(allNo)
return arr;
}
在这里我展示的是我这个项目的路由挑选的逻辑,数据结构是一定的,如果你的数据结构和我的不一样就需要写一个适合自己权限结构的挑选逻辑.