RABC权限管理(详细)
RABC权威设计理念 为了在不同账户(员工和总裁)登录系统后看到不同的页面,执行不同的功能,RABC(Role-Based Access control)权限模型是根据角色的权限来分配可视化页面。 三个关键点: 用户:使用系统的人 角色:使用系统的人的职位是什么(员工、经理、总裁) 权限点:职位可以做什么(左侧菜单栏功能模块->增删改查) 测试过程: 1 在员工管理页面添加员工。这是三要素的使用者
RABC权威设计理念
为了在不同账户(员工和总裁)登录系统后看到不同的页面,执行不同的功能,RABC(Role-Based Access control)权限模型是根据角色的权限来分配可视化页面。
三个关键点:
用户:使用系统的人
角色:使用系统的人的职位是什么(员工、经理、总裁)
权限点:职位可以做什么(左侧菜单栏功能模块->增删改查)
测试过程:
1 在员工管理页面添加员工。这是三要素的使用者
2 为新员工分配角色
3 在公司设置中为角色分配权限
💢 系统中的权限不能随意添加。必须有开发权限(左侧菜单栏可实现的页面)
💢 用户和角色之间是一对多的关系,一个人有多个角色。
具体实现
1\。分配角色
单击分配角色和弹出框,其中包含现有角色的列表。点击Assign role时,传递id,根据id显示当前用户已有的角色。
分配角色父组件src/employees/employee vue
<模板槽范围u003d“范围”>
<el-button typeu003d"text" sizeu003d"smell" @clicku003d"assignFn(scope.row)">分配角色</el-button>
</模板>
<对话框
titleu003d"分配角色"
:visible.asyncu003d"showDialog 角色"
:close-on-press-escapeu003d"false"
:close-on-click-modalu003d"false"
@closeu003d"showDialog 角色u003dfalse"
<assign-role :idu003d"curId" refu003d"assignRole" @closeu003d"showDialogRoleu003dfalse" />
</the-dialog>
//导入导入恢复框子组件
// --------------------------------------------分配角色-- --------------------------------
assignFn(行){
this.showDialogRole u003d true
this.curId u003d row.id
this.$nextTick(() u003d> {
this.$refs.assignRole.getRoleListFn()
})
}
分配角色的子组件:employees/assignrole vue
<模板>
<div>
<el-checkbox-group v-modelu003d"rolesList">
<el-checkbox v-foru003d"item in checkList" :keyu003d"item.id" :labelu003d"item.id">{{ item.name }}</el-checkbox>
</el-checkbox-group>
<div styleu003d"margin-top: 20px; text-align: right">
<el-button typeu003d"primary" @clicku003d"submitFn">确定</el-button>
<el-button @clicku003d"closeDialog">取消</el-button>
</div>
</div>
</模板>
<脚本>
从“@/api/settings”导入 {getAllRoleAPI}
从 '@/api/user.js' 导入 { getDetailInfo }
从“@/api/employees.js”导入 {assignRolesAPI}
导出默认 {
名称:'分配角色',
道具:{
id:{类型:字符串,必需:true}
},
数据() {
返回{
checkList: [], // 角色列表
rolesList: []// 用户已有角色
}
},
创建() {
},
方法:{
// ------------------------提交角色---------- --------------------------
异步提交Fn() {
const resp u003d await assignRolesAPI({ id: this.id, roleIds: this.rolesList })
控制台.log(resp)
this.$emit('关闭')
},
// ----------------------获取角色列表---------- ----------------------
异步 getRoleListFn() {
const resp u003d await getAllRoleAPI({ page: 1, pagesize: 100 })
控制台.log(resp)
this.checkList u003d resp.data.rows
const res u003d 等待 getDetailInfo(this.id)
控制台日志(资源)
this.rolesList u003d res.data.roleIds
},
// -------------------------取消按钮-------- ----------------------------
关闭对话框() {
this.$emit('关闭')
}
}
}
</脚本>
💢 El checkbox group v-model u003d "rolesList"中,v-model的绑定值是一个数组,表示可以多选。
💢 在模板中渲染数据时
{{ 项目名 }}
其中 label 确定当前选择的值,{{要显示的角色名称}}
2.分配权限
在父组件中(Views/settings/settings.vue):准备弹窗->注册事件->提供数据方法
<模板>
<div classu003d"settings-container">
<div classu003d"app-container">
<el卡>
<!-- 具体的页面结构 -->
<困惑>
<!-- 放置选项卡 -->
<el-tab-pane labelu003d"角色管理">
<!-- 表格 -->
<el-table :datau003d"tableList">
<el-table-column labelu003d"操作">
<!-- scope 只是插槽的名称。重要的是里面的名字。row 这个是每一行的对象,是固定的写法 -->
<模板槽范围u003d“范围”>
<el-button sizeu003d"small" typeu003d"success" @clicku003d"hAssign(scope.row.id)">分配权限</el-button>
</模板>
</el-table-column>
</the-table>
<el-row typeu003d"flex" justifyu003d"center" alignu003d"middle" styleu003d"height: 60px">
</el-row>
</el-tab-pane>
</歧义>
</el-card>
<!-- 用于分配权限的炸弹层-->
<对话框
titleu003d"分配权限(一级为路由页面的查看权限-二级为按钮操作权限)"
:visible.asyncu003d"showDialog 分配"
<assign-permission refu003d"assignPermission" :role-idu003d"roleId" @closeu003d"showDialogAssignu003dfalse" />
</the-dialog>
</div>
</div>
</模板>
<脚本>
导出默认 {
名称:'设置',
组件:{
分配权限
},
数据() {
返回{
showDialogAssign: false, // 分配权限对话框
方法:{
// -----------------------------分配权限---- ---------------------------------
分配(ID){
this.roleId u003d id
this.showDialogAssign u003d true
this.$nextTick(() u003d> {
this.$refs.assignPermission.getRoleDetail()
})
}
}
}
</脚本>
在子组件(settings/assignPermission.vue)中:
<模板>
<div>
<!-- 权限点数据显示:勾选-严格设置为true,可以关闭父子关联 -->
<树
参考 u003d“树”
:datau003d"permissionData"
:propsu003d"{ 标签: '名称' }"
节点键u003d"id"
默认扩展所有
:show-checkboxu003d"true"
:check-strictlyu003d"true"
/>
<div styleu003d"text-align:right;">
<el-button @clicku003d"hCancel">取消</el-button>
<el-button typeu003d"primary" @clicku003d"getAssignRoleFn">确定</el-button>
</div>
</div>
</模板>
<脚本>
从“@/api/permissions.js”导入 { getPermissionListAPI}
从“@/utils/index.js”导入 { tranListToTreeData }
从 '@/api/settings.js' 导入 { getRoleDetail, getAssignRoleAPI }
导出默认 {
道具:{
角色标识:{
类型:字符串,
必需:真
}
},
数据() {
返回{
permissionData: [] // 存储权限数据
}
},
创建() {
this.getPermissionListFn()
},
方法:{
// --------------------------------------------获取权限列表- ----------------------------------
异步 getPermissionListFn() {
const resp u003d 等待 getPermissionListAPI()
控制台.log(resp)
this.permissionData u003d tranListToTreeData(resp.data)
console.log('数组到树', this.permissionData)
},
// --------------------------------------------获取角色详细信息----------------------------------
异步 getRoleDetail() {
const resp u003d 等待 getRoleDetail(this.roleId)
控制台.log(resp)
// 回填到树
this.$refs.tree.setCheckedKeys(resp.data.permIds)
},
// ---------------------------------关闭炸弹层-----------------------------
hCancel() {
// 通过父组件关闭spring层
this.$emit('关闭')
// 下次根据id获取角色权限数组时,清空容器,以免影响下次保存
this.$refs.tree.setCheckedKeys([])
},
// ------------------------------为角色分配权限- -------------------------------------
异步 getAssignRoleFn() {
const pid u003d this.$refs.tree.getCheckedKeys()
const resp u003d await getAssignRoleAPI({ id: this.roleId, permIds: pid })
控制台.log(resp)
this.hCancel()// 通知父组件关闭炸弹层
this.$message.success('分配成功')
}
}
}
</脚本>
<样式>
</style>
3.页面权限控制
1\。左侧菜单权限控制(不同用户进入系统后会看到不同的菜单)
2.操作按钮权限控制(不同人对页面按钮的权限不同)
3.权限数据的位置:下图为管理员登录时可以看到的权限![在此处插入图片说明](https://img-blog.csdnimg.cn/5bb6a3a086d6498c911224f19bc2840e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5YuH5pWi54mb54mb77yM5Yay5Yay5Yay,size_11,color_FFFFFF,t_70,g_se,x_16)3.1 修改权限数据
只有管理员才能修改权限数据,所以先添加用户->分配角色->分配权限,重新观察权限数据(data.roles.menu,
点)
3.2 动态生成左侧菜单
新用户登录成功,页面跳转进入导航守卫
3.3 在router/index JS中的路由配置中,删除动态路由的部分改为:routes:[...constantRoutes]
3.4 在权限JS中,用addRoutes动态添加。这时候,左边的动态路由就只剩下静态主页了。可以在地址栏输入地址跳转(addRoutes的作用)
3.5 从动作中返回菜单项
异步获取用户信息(上下文){
// 1.ajax获取基本信息,包括用户id
const rs u003d 等待 getUserInfoApi()
console.log('用于获取用户信息,', rs)
// 2.根据用户id(rs.data.userId)重新发送请求,获取详细信息(包括头像)
常量信息 u003d 等待 getUserDetailById(rs.data.userId)
console.log('获取详细信息', info.data)
// 合并上面得到的两个副本,保存到vuex
context.commit('setUserInfo', { ...info.data, ...rs.data })
// 当前用户可以看到菜单 res.data 角色。菜单
- 返回 rs.data.roles.menus
},
3.6 在权限中获取JS中action的返回值并过滤
/ 引入所有动态路由表(未过滤)
- 导入路由器,{ asyncRoutes } from '@/router'
const whiteList u003d ['/login', '/404']
router.beforeEach(async(to, from, next) u003d> {
// 打开进度条
NProgress.start()
// 获取本地token全局getter
常量令牌 u003d store.getters.token
如果(令牌){
// 有一个令牌
if (to.path u003du003du003d '/login') {
下一个('/')
} 其他 {
if (!store.getters.userId) {
- const menus u003d await store.dispatch('user/getUserInfo')
//按权限过滤动态数组
- const filterRoutes u003d asyncRoutes.filter(route u003d> {
- const routeName u003d route.children[0].name
- return menus.includes(routeName)
- })
// 1.重写为动态加法
- router.addRoutes(filterRoutes)
//2。生成左侧菜单时,也应该从 vuex 中获取
- store.commit('menu/setMenuList', filterRoutes)
- //3。解决刷新时白屏bug
next({ ...to, // 确保在进入页面之前添加了路由(可以理解为再次进入)
replace: true// 不保留重复历史再次返回
})
}其他{
下一个()
}
} 其他 {
//
if (whiteList.includes(to.path)) {
下一个()
} 其他 {
下一个('/登录')
}
}
// 结束进度条
NProgress.done()
})
💢当前菜单(src\layout\components\Sidebar\index.vue)使用的数据:this.$router.options.routes **可以获取当前路由配置和设置的路由表数据\ **但是这个数据是固定的,所以把这个数据替换成this.$router.options.routes就可以动态获取路由表的数据了。
💢 如果想在调用 addRoutes 方法后立即在左侧菜单栏中显示路由表数据,请将动态路由菜单保存在 vuex 中
3.7 修复bug
3.7. 1 解决刷新白屏问题(//3...)
3.7. 2 退出后重新登录,发现菜单异常(控制台有输出说路由重复)
原因:路由设置是通过路由器Addroutes(filterroutes)添加的。退出时不清除。重新登录再添加一次,就这样重复了。
需要重新设置路由权限(恢复默认),以后登录后再添加。否则会重复添加
解决:
router/index.js 文件,有reset路由方法
// 重置路由
导出函数resetRouter() {
常量 newRouter u003d createRouter()
router.matcher u003d newRouter.matcher // 重置路由的匹配路径
}
注销时可以调用store/modules/user js
从“@/路由器”导入 {resetRouter}
// 退出动作
注销(上下文){
// 1.删除vuex个人信息
context.commit('removeUserInfo')
// 2. 移除token信息
context.commit('removeToken')
// 3. 重置路由
- 重置路由器()
}
4.按钮级别控制
4.1 用户自定义指令:自定义指令。因为指令是不够的,我们需要自己定义。
4.2 解决按钮级权限验证-在主JS中,定义全局指令
// 注册一个全局自定义指令 ` v-allow`
Vue.directive('允许', {
插入:函数(el,绑定){
// 从 vuex 中取点,
常量点 u003d store.state.user.userInfo.roles.points
// 如果点有绑定值则显示
if (points.includes(binding.value)) {
// console.log('判断这个元素是否会显示', el, binding.value)
} 其他 {
// el.style.display u003d 'none',这只是隐藏的。懂业务的也可以通过检查显示,所以应该销毁
el.parentNode.removeChild(el)
}
}
})
利用
<el-按钮
- v-allowu003d"'import_employee'"
类型u003d"警告"
尺寸u003d“小”
@clicku003d"$router.push('/import')"
导入excel</el-button>
※这里:'import_'employee'来自一个标识符
更多推荐
所有评论(0)