问题背景
技术栈:Vue及Vue周边、Axios库、Element-ui库、Echart库等;
项目简单介绍:中大型管理平台、使用角色众多、页面复杂;
需要做权限控制的地方:1.页面是否有权限进入;2.操作按钮是否有权限展示3.接口是否有权限调用。
接下来针对这三处一一简单总结: 首先,我们会通过超管配置用户的操作权限,反应到接口这就是在用户登录后,会返回一个对象-其中包含着该用户的所有页面有的权限,前端通过处理该对象展示或隐藏对应页面、按钮。
页面层的控制
这里主要通过Vue-router的全局路由控制。
路由元信息(meta)
在路由创建时可以提供meta配置角色,结合后端返回的当前用户角色判断该路由(页面)当前用户有无权限访问。例:
routes: [
{
path: '/login',
name: 'login',
meta: {
roles: ['admin', 'user']
},
component: () => import('../components/Login.vue')
},
{
path: 'home',
name: 'home',
meta: {
roles: ['admin']
},
component: () => import('../views/Home.vue')
},
]
main.js中进行路由控制,代码如下:
//假设有两种角色:admin 和 user
//从后台获取的用户角色
const role = 'user'
//当进入一个页面是会触发导航守卫 router.beforeEach 事件
router.beforeEach((to,from,next)=>{
if(to.meta.roles.includes(role)){
next() //放行
}esle{
next({path:"/404"}) //跳到404页面
}
})
若无权限则可跳到404或无权限页面
动态加载菜单和路由
有时为了安全,我们会根据后端返回用户角色来动态添加菜单和路由表。vue-router提供了addRoutes()方法,可以动态注册路由,需要注意的是,动态添加路由是在路由表中push路由,由于路由是按顺序匹配的,因此需要将诸如404页面这样的路由放在动态添加的最后。 这里需要保证路由对应的页面在项目里有。
页面内操作按钮控制
超管做配置时,对应页面对应操作有固定的格式,例XXX:XXX,然后该数据交由前端处理。我们这个封装一个全局的Vue指令,控制按钮的显隐。例:
import { getConfigElement } from '@/lib/utils'
export default {
inserted(el, { value }, vnode) {
if (value && value.includes(':')) {
const auths = value.split(':')
const pageElement = getConfigElement(auths[0])
const btnName = auths[1]
if (!pageElement[btnName]) {
el.style.display = 'none'
return
}
}
}
}
这里el改变了display,也可以选择移除,代码如下:
el.parentNode && el.parentNode.removeChild(el)
其中,getConfigElement即登录后接口返回的用户所有有的权限。该指令通过注入DOM元素,将元素Button代表的语义匹配getConfigElement对象,来决定该DOM元素的显隐。使用过程如下:
<el-button
v-if="item.type == 'button'"
:key="index"
v-hasAuth="item.authCode"
:disabled="item.isDisabled"
:class="item.className"
class="nav-form-btn"
@click.stop.prevent="item.handleClick"
>
{{ item.innerText }}
</el-button>
对应的authCode乃用户自定义的该按钮的语义,例:
authCode: 'myBpFieldUnitCar:unreview'
页面按钮的权限处理即如此。需要说明的是,控制display属性按钮消失可能会打乱页面布局,这里需要UI设计师考虑下是否启用按钮禁用。
接口是否有权限
这里主要后端处理,前端正常调用即可,如果用户无权限,后端可统一格式返回,前端抛出即可。
谢谢拨冗浏览
参考文章: juejin.cn/post/684490…