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

采用技术:Vue.js + Vuex + Element UI
实现 RBAC 权限管理需要后端接口支持,这里仅提供前端解决方案。
因代码篇幅较大,对代码进行了删减,文中 “...” 即为省略的一部分代码。
大致思路:
首先登录成功后,从后台拉取用户当前可显示的菜单和可用权限列表,分别将其存入 store 的 nav(菜单导航) 和 auth(用户可用权限) 中,在用户切换路由时,判断是否存在 auth ,如果不存在,则重新获取,判断当前访问地址 to.meta.alias 是否在用户可用权限列表中,如果不存在,则提示无权限,否则进入路由。
1. 路由与侧边菜单分离
侧边菜单相关代码 Main.vue
<template>
<!-- ... -->
<aside :class="collapsed?'menu-collapsed':'menu-expanded'">
<!--导航菜单-->
<el-menu :default-active="$route.path"
class="el-menu-vertical-aliyun"
@open="handleopen"
@close="handleclose"
@select="handleselect"
:collapse="collapsed"
unique-opened router>
<template v-for="(item,index) in nav">
<!-- 二级菜单 -->
<el-submenu :index="index+''"
v-if="item.children && item.children.length > 0">
<!-- 二级菜单顶级 -->
<template slot="title">
<i :class="['icon',item.iconCls]"></i>
<span slot="title">{{item.name}}</span>
</template>
<!-- 二级菜单下级 -->
<el-menu-item-group>
<!--<span slot="title">{{item.name}}</span>-->
<!-- && child.url-->
<template v-for="child in item.children">
<!--无三级菜单-->
<el-menu-item
:index="child.url"
:key="child.url"
v-if="!child.children">
{{child.name}}
</el-menu-item>
<!--有三级菜单-->
<el-submenu
:index="child.url"
:key="child.url"
v-if="child.children">
<span slot="title">{{child.name}}</span>
<el-menu-item v-for="subChild in child.children"
:index="subChild.url"
:key="subChild.url">
{{subChild.name}}
</el-menu-item>
</el-submenu>
</template>
</el-menu-item-group>
</el-submenu>
<!-- 一级菜单 -->
<el-menu-item v-if="!item.children"
:index="item.url">
<i :class="['icon',item.iconCls]"></i>
<span slot="title">{{item.name}}</span>
</el-menu-item>
</template>
</el-menu>
</aside>
<!-- ... -->
</template>
<script>
export default {
// ...
computed: {
// 从 Vuex 中获取导航菜单
nav() {
return this.$store.state.nav;
}
}
// ...
}
</script>
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"
]
}
}
存在的问题
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# vuejs
# 权限管理
# Vue.js
# RBAC角色权限管理
# RBAC角色权限
# vue2模拟vue-element-admin手写角色权限的实现
# vue router权限管理实现不同角色显示不同路由
# vue3使用element-plus搭建后台管理系统之菜单管理功能
# 详解vue后台系统登录态管理
# vue后台系统管理项目之角色权限分配管理功能(示例详解)
# 跳转
# 后端
# 不存在
# 组织结构
# 将其
# 大神
# 采用了
# 项目管理
# 上还
# 即为
# 大家多多
# 进行了
# 到该
# 物业管理
# 判断是否
# 数据查询
# 无法访问
# 加载
# 列表中
# export
相关文章:
为什么Go需要go mod文件_Go go mod文件作用说明
建站主机如何安装配置?新手必看操作指南
香港服务器部署网站为何提示未备案?
胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?
高端建站如何打造兼具美学与转化的品牌官网?
电脑免费海报制作网站推荐,招聘海报哪个网站多?
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
建站主机选哪种环境更利于SEO优化?
小自动建站系统:AI智能生成+拖拽模板,多端适配一键搭建
,网站推广常用方法?
如何做网站制作流程,*游戏网站怎么搭建?
魔毅自助建站系统:模板定制与SEO优化一键生成指南
如何在阿里云完成域名注册与建站?
浙江网站制作公司有哪些,浙江栢塑信息技术有限公司定制网站做的怎么样?
php能控制zigbee模块吗_php通过串口与cc2530 zigbee通信【介绍】
如何确认建站备案号应放置的具体位置?
建站之星如何取消后台验证码生成?
如何生成腾讯云建站专用兑换码?
c# await 一个已经完成的Task会发生什么
如何通过主机屋免费建站教程十分钟搭建网站?
专业网站制作企业网站,如何制作一个企业网站,建设网站的基本步骤有哪些?
盘锦网站制作公司,盘锦大洼有多少5G网站?
建站之星logo尺寸如何设置最合适?
宁波免费建站如何选择可靠模板与平台?
香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南
C++用Dijkstra(迪杰斯特拉)算法求最短路径
在线流程图制作网站手机版,谁能推荐几个好的CG原画资源网站么?
如何获取免费开源的自助建站系统源码?
如何快速搭建安全的FTP站点?
如何通过宝塔面板实现本地网站访问?
Android使用GridView实现日历的简单功能
如何选择高效稳定的ISP建站解决方案?
如何用免费手机建站系统零基础打造专业网站?
企业微网站怎么做,公司网站和公众号有什么区别?
制作宣传网站的软件,小红书可以宣传网站吗?
如何快速生成凡客建站的专业级图册?
如何通过虚拟主机快速完成网站搭建?
高防服务器如何保障网站安全无虞?
香港服务器租用费用高吗?如何避免常见误区?
如何快速搭建虚拟主机网站?新手必看指南
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
c# Task.Yield 的作用是什么 它和Task.Delay(1)有区别吗
公司网站的制作公司,企业网站制作基本流程有哪些?
专业网站设计制作公司,如何制作一个企业网站,建设网站的基本步骤有哪些?
整人网站在线制作软件,整蛊网站退不出去必须要打我是白痴才能出去?
微网站制作教程,不会写代码,不会编程,怎么样建自己的网站?
Python文件管理规范_工程实践说明【指导】
如何通过VPS搭建网站快速盈利?
电商网站制作价格怎么算,网上拍卖流程以及规则?
济南网站建设制作公司,室内设计网站一般都有哪些功能?
*请认真填写需求信息,我们会在24小时内与您取得联系。