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'来自一个标识符

Logo

前往低代码交流专区

更多推荐