记录一下中大型管理项目中的权限控制问题

631 阅读3分钟

问题背景

技术栈: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…