博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用 Vue.js 实现前后端分离的RBAC角色权限管理
阅读量:6691 次
发布时间:2019-06-25

本文共 7515 字,大约阅读时间需要 25 分钟。

项目背景:物业管理后台,不同角色拥有不同权限

采用技术:Vue.js + Vuex + Element UI

实现 RBAC 权限管理需要后端接口支持,这里仅提供前端解决方案。
因代码篇幅较大,对代码进行了删减,文中 “...” 即为省略的一部分代码。

大致思路:

首先登录成功后,从后台拉取用户当前可显示的菜单和可用权限列表,分别将其存入 store 的 nav(菜单导航) 和 auth(用户可用权限) 中,

在用户切换路由时,判断是否存在 auth ,如果不存在,则重新获取,判断当前访问地址 to.meta.alias 是否在
用户可用权限列表中,如果不存在,则提示无权限,否则进入路由。

1. 路由与侧边菜单分离

侧边菜单相关代码 Main.vue

2. 路由切换前进行鉴权

路由定义的部分代码,对每个路由添加了 meta 属性,用于鉴权。

这里 component 采用了异步引入的方式。

定义路由

// ...// 系统管理{path: '/system',component: Main,name: '系统管理',redirect: '/system/organization',children: [{  path: '/system/organization',  component: () => import ('@/views/System/Organization.vue'),  name: '组织结构',  // requiresAuth 用于确认此地址是否需要验证  // alias 用于获取后端返回rbac权限对应的前端路由地址和导航菜单图标  meta: {requiresAuth: true, alias: 'Pmsadmin/Oragnize/list'}},  {    path: '/system/user',    component: () => import ('@/views/System/User.vue'),    name: '人员管理',    redirect: '/system/user/index',    children: [    {      path: '/system/user/index',      component: () => import ('@/views/System/UserList.vue'),      name: '职员列表',      meta: {requiresAuth: true, alias: 'Pmsadmin/Admin/list'}    }    ]  },  {    path: '/system/auth',    component: () => import ('@/views/System/Auth.vue'),    name: '角色管理',    meta: {requiresAuth: true, alias: 'Pmsadmin/Role/list'}  }]}// ...

路由钩子 beforeEach

router.beforeEach((to, from, next) => {  document.title = `${configs.title} - ${to.name}`;  const {hasAuth, auth} = store.state.user;  // 未拿到权限,则获取  if (!hasAuth) {    store.dispatch('getUserAuth');    console.log('重新获取用户权限');    // next();  }  // 如果未登录,跳转  if (window.localStorage.getItem('IS_LOGIN') === null && to.path !== '/login') {    console.log('未登录状态');    next({      path: '/login',      query: {redirect: to.fullPath}      // 将跳转的路由path作为参数,登录成功后跳转到该路由    })  } else {    // 需要鉴权的路由地址    console.log(to, auth.indexOf(to.meta.alias), auth);    if (to.meta.requiresAuth) {      if (auth.indexOf(to.meta.alias) > -1) {        console.log('有权限进入');        next();      } else {        if(auth.length > 0) {          Message.error({            message: '当前用户权限不足,无法访问',            showClose: true,          });        } else {          next();        }      }    } else {      next();    }  }});

在 Vuex 的 state 中,定义好 nav 对象

// 登录用户信息const user = {  name: '', // 用户名  avatar: '', // 用户头像  auth: [], // 用户权限  hasAuth: false // 是否已经加载用户权限};// 导航菜单const nav = [];

通过 action 异步获取数据

// 获取用户权限const getUserAuth = async ({commit}) => {  const res = await http.post('YOUR_URL', {});  if (res === null) return;  console.log('getUserAuth', res.param);  commit('SET_USER_AUTH', res.param.auth);  commit('SET_SIDE_NAV', res.param.nav);};

Vuex 中的 mutation 的相关代码

// 设置用户权限const SET_USER_AUTH = (state, auth) => {  state.user.auth = auth.concat('欢迎使用');  state.user.hasAuth = true;};// 设置导航菜单const SET_SIDE_NAV = (state, nav) => {  // 导航菜单  let _nav = [{    name: '欢迎使用',    url: "/main",    iconCls: 'fa fa-bookmark'  }];  // 权限菜单对应的路由地址  const route = {    "系统管理": {iconCls: 'fa fa-archive', url: ''},    "Pmsadmin/Oragnize/list": {iconCls: '', url: '/system/organization'},    "Pmsadmin/Admin/list": {iconCls: '', url: '/system/user/index'},    "Pmsadmin/Role/list": {iconCls: '', url: '/system/auth'},    "Pmsadmin/Log/record": {iconCls: '', url: '/system/logs'},    "项目管理": {iconCls: 'fa fa-unlock-alt', url: ''},    "Pmsadmin/Project/list": {iconCls: '', url: '/project/list/index'},    "Pmsadmin/House/list": {iconCls: '', url: '/project/house'},    "Pmsadmin/Pack/list": {iconCls: '', url: '/project/pack'},    "广告位": {iconCls: 'fa fa-edit', url: ''},    "Pmsadmin/Place/list": {iconCls: '', url: '/adsplace/list'},    "投诉建议": {iconCls: 'fa fa-tasks', url: ''},    "Pmsadmin/Scategory/list": {iconCls: '', url: '/complain/type'},    "Pmsadmin/Complain/list": {iconCls: '', url: '/complain/list'},    "Pmsadmin/Suggest/list": {iconCls: '', url: '/complain/suggestion'},    "报事报修": {iconCls: 'fa fa-user', url: ''},    "Pmsadmin/Rcategory/list": {iconCls: '', url: '/rcategory/type'},    "Pmsadmin/Rcategory/info": {iconCls: '', url: '/rcategory/public'},    "Pmsadmin/Repair/list": {iconCls: '', url: '/rcategory/personal'},    "便民服务": {iconCls: 'fa fa-external-link', url: ''},    "Pmsadmin/Bcategory/list": {iconCls: '', url: '/bcategory/type'},    "Pmsadmin/Service/list": {iconCls: '', url: '/bcategory/list'},    "首座推荐": {iconCls: 'fa fa-file-text', url: ''},    "Pmsadmin/stcategory/list": {iconCls: '', url: '/stcategory/type'},    "Pmsadmin/Store/list": {iconCls: '', url: '/stcategory/list'},    "招商租赁": {iconCls: 'fa fa-leaf', url: ''},    "Pmsadmin/Bussiness/list": {iconCls: '', url: '/bussiness/list'},    "Pmsadmin/Company/list": {iconCls: '', url: '/bussiness/company'},    "Pmsadmin/Question/list": {iconCls: '', url: '/bussiness/question'},    "停车找车": {iconCls: 'fa fa-ra', url: ''},    "Pmsadmin/Cplace/list": {iconCls: '', url: '/cplace/cmanage'},    "Pmsadmin/Clist/list": {iconCls: '', url: '/cplace/clist'},    "Pmsadmin/Cquestion/list": {iconCls: '', url: '/cplace/cquestion'},  };  for (let key in nav) {    let item = nav[key];    let _temp = {};    let subItems = []; // 二级菜单临时数组    if (item.children && item.children.length > 0) {      // 二级菜单      item.children.forEach(subItem => {        subItems.push(Object.assign({}, {          name: subItem.name || '',          url: route[subItem.url].url || '',          iconCls: route[subItem.url].iconCls || '',        }))      });      // 一级菜单      _temp = Object.assign({}, {        name: item.name || '',        url: item.url || '',        iconCls: route[item.name].iconCls || '',        children: subItems.slice(0)      });      _nav.push(_temp);    }  }  state.nav = _nav;};

3. 后端接口返回内容

{    "status": 200,    "info": "数据查询成功!",    "param": {        "nav": {            "1": {                "name": "系统管理",                "url": "",                "children": [                    {                        "name": "组织结构",                        "url": "Pmsadmin/Oragnize/list"                    },                    {                        "name": "人员管理",                        "url": "Pmsadmin/Admin/list"                    },                    {                        "name": "角色管理",                        "url": "Pmsadmin/Role/list"                    },                    {                        "name": "日志管理",                        "url": "Pmsadmin/Log/record"                    }                ]            },            "61": {                "name": "广告位",                "url": "",                "children": [                    {                        "name": "广告位列表",                        "url": "Pmsadmin/Place/list"                    }                ]            }        },        "auth": [            "系统管理",            "Pmsadmin/Oragnize/list",            "Pmsadmin/Admin/list",            "Pmsadmin/Role/list",            "Pmsadmin/Log/record",            "广告位",            "Pmsadmin/Place/list"        ]    }}

存在的问题

新增 修改 删除 按钮还无法实现根据用户权限控制其显示

代码上还存在着不足,期待大神能够有更优的解决方案。

前端代码

可参考:

如果有更好的想法和建议,欢迎评论。

转载地址:http://odeao.baihongyu.com/

你可能感兴趣的文章
两天快速开发一个自己的微信小程序
查看>>
z-index兼容问题:关于ie6/7下的z-index
查看>>
GOLANG SDK下载
查看>>
前端 JS POST提交
查看>>
SQL SERVER 事务处理通用模板
查看>>
js 多选选择删除数据
查看>>
如何创建一个完整的CRM工程
查看>>
学习内容
查看>>
[C#].Net Core下全局自定义身份过滤器使用AllowAnonymous属性
查看>>
常见数组&字符串API及其应用场景总结
查看>>
Codeforces Round #403 (Div. 2, based on Technocup 2017 Finals)
查看>>
Codeforces Round #204 (Div. 2)
查看>>
AJAX 获取Servlet文件路径
查看>>
软件测试之Monkey 初步了解(入门级)
查看>>
log日志应用 自定义的log
查看>>
Delphi2010/XE2下隐藏程序系统任务栏的图标
查看>>
文件编码问题
查看>>
linux虚拟机的scsi设备id与盘符不一致问题的解决
查看>>
高薪源于专注和极致!
查看>>
CSVDE批量导入域用户
查看>>