什么是权限控制
在项目中,尤其是在后台管理系统中,不同人员登陆,看到的页面菜单是不一样的,除了页面的权限,还会有一些按钮级别的权限,比如一个下载按钮,有的帐号可以用,有的人不能用。
所以权限控制基本可以总结为两种情况
1.页面级的权限(用户是否有权限能看到这个页面)
2.按钮级的权限(用户是否能看到或者能用页面中的某个按钮)
页面级权限控制
后端返回路由权限名,前端存储完整路由权限表,并动态生成路由
首先前端router.js文件存储的路由配置信息会分为两部分,分别是需要权限的和不需要权限的。
页面一开始不能一个路由没有,所以会有一些不需要权限的页面,比如登录页,404页面等。所以一开始直接渲染
这个不需要权限的路由表,等后台返回之后再把需要权限的路由加到当前路由里面形成一个全新的路由表就可以了
router.js 不需要权限的路由表
const route = [
{
path: '/',
redirect: '/login',
},
{
path: '/login',
name: '登录页面',
component: ()=>import("@/views/login.vue")
},
{
path: '/404',
name: '404页面',
component: ()=>import("@/views/404.vue")
},
]
router.js 需要权限的路由表
对于需要权限的页面,我们在路由中的meta属性里添加了一个字段roles,表示当前路由所需要的权限.
注意这个roles并不是关键字,叫别的名字也行。至于meta为什么值是一个数组,是我们考虑到将来有些页面可能不同的权限都能看,比如普通用户,管理员,超级管理员
export const asyncRouterMap = [
{
path: '/permission',
name: 'permissionhome',
meta: {
icon: 'el-icon-setting',
roles: ['admin','superadmin']
},
component: ()=>import("@/views/permission.vue")
},
{
path: '/detail',
name: 'detail',
meta: {
icon: 'el-icon-setting',
roles: ['superadmin']
},
component: ()=>import("@/views/detail.vue")
},
当用户登录之后,登陆接口会返回一个权限名字的字符串类似于如下结构
{
code:200,
success:true,
result:{
name:"张三",
opid:11024,
role:"admin"//此字段是拥有的权限名字
}
}
拿到这个权限名字之后,去循环我们写好的那个需要权限的路由表进行挨个比较,
具体操作
引入我们的异步路由表,然后做一个循环
将筛选之后的路由表,通过一个方法加入到当前项目的路由中。通过调用根路由实例的这个方法,就可以实现把任意一个路由配置加入到当前页面路由中,由此就可以生成一个新的路由。达到了真正控制权限的目的
router.addRoute(筛选之后的路由表)
//引入我们的异步路由表,然后做一个循环
import router from "./router" //不需要权限的
import asyncRoutes from "./asyncRouterMap"//需要权限的
async function getAsyncRouter(Token,to,next){
//通过Token从后端获取role
const {role} = await post("/nav",Token)
//循环需要权限的路由
for(let i=0; i<asyncRoutes.length; i++){
//判断是不是404配置对象
if(i<asyncRoutes.length-1){
//获取路由列表中role权限
const auth = asyncRoutes[i].meta.roles
for(let item=0; item<auth.length; item++){
//获取到的role值匹配
if(role == auth[item]){
//添加到router路由表中
router.addRoute(asyncRoutes[i])
}
}
}else{
router.addRoute(asyncRoutes[i])
}
}
//防止路由没添加好就next,加好to.name不为空走else的next,
next({...to,replace:true})
}
注意:因为addRoute添加的路由刷新页面会丢失,所以getAsyncRouter这个函数需要在全局路由守卫调用,每次路由跳转重新添加
按钮级权限控制(一)
比如某个按钮只有超级管理员能看到,其他权限看不到,那么按照上面第一种说法,我们从返回信息拿到role字段
那么页面中的按钮可以这么写
<button v-if="role=='superAdmin'">权限按钮</button>
export default{
computed:{
//当然实际工作中这里一般都使用mapState
role:this.$store.state.role
}
}
这样其实就能实现按钮级别的权限控制。特殊情况如果role是数组,那么可以用indexOf方法去查找一下权限数组中包不包含我这个按钮需要的权限,原理几乎不变
按钮级权限控制(二)
第二种方式是通过自定义指令,原理大致相同
1.首先还是取出后端返回的权限的名字
2.全局定义一个自定义指令
Vue.directive('per', {
bind: (el, binding, vnode) => {
//roles是我们的权限数组,binding.value是我们传入自定义指令的值
//如果找不到,那证明没有权限,把当前元素节点移除掉
if (roles.indexOf(binding.value)==-1) {
el.parentNode.removeChild(el);
}
}
使用
//这个传入的admin是对应上面binding.value
<div v-per="[admin]">
admin 可见
</div>