项目背景:物业管理后台,不同角色拥有不同权限
采用技术:Vue.js + Vuex + Element UI
实现 RBAC 权限管理需要后端接口支持,这里仅提供前端解决方案。
因代码篇幅较大,对代码进行了删减,文中 “...” 即为省略的一部分代码。
大致思路:
首先登录成功后,从后台拉取用户当前可显示的菜单和可用权限列表,分别将其存入 store 的 nav(菜单导航) 和 auth(用户可用权限) 中,在用户切换路由时,判断是否存在 auth ,如果不存在,则重新获取,判断当前访问地址 to.meta.alias 是否在用户可用权限列表中,如果不存在,则提示无权限,否则进入路由。1. 路由与侧边菜单分离
侧边菜单相关代码 Main.vue
2. 路由切换前进行鉴权
路由定义的部分代码,对每个路由添加了 meta 属性,用于鉴权。
这里 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: '角色管理',alias: 'Pmsadmin/Role/list'}
}
]
}
// ...
路由钩子 beforeEach
{
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 对象
通过 action 异步获取数据
{
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 的相关代码
{
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',"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',"Pmsadmin/Place/list": {iconCls: '',url: '/adsplace/list'},"投诉建议": {iconCls: 'fa fa-tasks',"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',"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',"Pmsadmin/Bcategory/list": {iconCls: '',url: '/bcategory/type'},"Pmsadmin/Service/list": {iconCls: '',url: '/bcategory/list'},"首座推荐": {iconCls: 'fa fa-file-text',"Pmsadmin/stcategory/list": {iconCls: '',url: '/stcategory/type'},"Pmsadmin/Store/list": {iconCls: '',url: '/stcategory/list'},"招商租赁": {iconCls: 'fa fa-leaf',"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',"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. 后端接口返回内容
存在的问题
- 新增 修改 删除 按钮还无法实现根据用户权限控制其显示
- 代码上还存在着不足,期待大神能够有更优的解决方案。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。