从下面的图片可以知道传统的权限是通过对每个用户进行权限分配设置的,但是这种方式已经不适合目前企业的高效管控权限的发展需求,因为每个人都要单独去设置权限
RBAC
基于此,RBAC的权限模型就应运而生了,RBAC(Role-Based Access control) ,也就是基于角色的权限分配解决方案,相对于传统案,RBAC提供了中间层Role(角色),其权限模式如下
RBAC实现了用户和权限点的分离,想对某个用户设置权限,只需要对该用户设置相应的角色即可,而该角色就拥有了对应的权限,这样一来,权限的分配和设计就做到了极简,高效,当想对用户收回权限时,只需要收回角色即可,接下来,我们就在该项目中实施这一设想
首先要实现分配角色
一个用户可以对应多个角色一个角色也可以对应多个权限,是一个一对多的关系
首先实现一下比较简单的分配角色
<template>
<el-dialog title="分配角色" :visible="showRoleDialog">
<!-- el-checkbox-group选中的是 当前用户所拥有的角色 需要绑定 当前用户拥有的角色-->
<el-radio-group v-model="roleId">
选项
</el-radio-group>
<el-row slot="footer" type="flex" justify="center">
<el-col :span="6">
<el-button type="primary" size="small">确定</el-button>
<el-button size="small">取消</el-button>
</el-col>
</el-row>
</el-dialog>
</template>
<script>
export default {
props: {
showRoleDialog: {
type: Boolean,
default: false
},
// 用户的id 用来查询当前用户的角色信息
userId: {
type: Number,
default: 0
}
}
}
</script>
获取角色列表和当前用户角色
assign-role.vue 中需要获取所有角色和用户当前的角色id,然后展示所有的角色名称,并勾选用户当前的角色,如果当前用户还没有角色,则不勾选任何角色
获取所有角色列表并展示
<!-- 分配角色 -->
<el-radio-group v-model="roleId">
<el-radio v-for="item in roleList" :key="item.id" :label="item.id">
{
{
item.roleName }}
</el-radio>
</el-radio-group>
获取角色列表api
import request from '@/utils/request'
export function getRoleList() {
return request({
url: 'roles',
method: 'get'
})
}
获取角色列表
import {
getRoleList } from '@/api/role'
export default {
props: {
showRoleDialog: {
type: Boolean,
default: false
},
userId: {
type: String,
default: null
}
},
data() {
return {
roleList: [],
roleIds: []
}
},
created() {
this.getRoleList()
},
methods: {
// 获取所有角色
async getRoleList() {
const res = await getRoleList()
this.roleList = res
}
}
}
获取用户当前角色
// 根据用户查看角色信息api
export function getRoleById(id) {
return request({
url: `users/${
id}`,
method: 'get'
})
}
获取用户的当前角色
import {
getRoleById } from '@/api/user'
async getUserDetailById(id) {
const {
roleIds } = await getUserDetailById(id)
this.roleIds = roleIds // 赋值本用户的角色
}
点击角色弹出层
// 编辑角色
async editRole(id) {
this.userId = id // props传值 是异步的
// 下面这里调用子组件的函数时,为什么一加入 await
await this.$refs.assignRole.getUserDetailById(id) // 父组件调用子组件方法
this.showRoleDialog = true
},
<!-- 放置角色分配组件 -->
<assign-role ref="assignRole" :show-role-dialog.sync="showRoleDialog" :user-id="userId" />
给用户分配角色
/** *
* 给用户分配角色
* ***/
// 为用户分配角色
export function assignRole(id, data) {
return request({
url: `users/${
id}/role`,
method: 'put',
data
})
}
async saveRole() {
await assignRole(this.userId, {
rid: this.roleId
})
// update:showRoleDialog 的用户解释
this.$emit('update:showRoleDialog', false)
this.$message.success('设置角色成功')
},
cancel() {
this.roleId = null
this.$emit('update:showRoleDialog', false)
}
在企业服务中,权限一般分割为 页面访问权限,按钮操作权限,API访问权限
API权限多见于在后端进行拦截,所以我们这一版本只做页面访问和按钮操作授权/
完成权限页面结构
<template>
<div class="dashboard-container">
<div class="app-container">
<!-- 靠右的按钮 -->
<common-tools>
<span slot="before">共100条记录</span>
<template slot="after">
<el-button size="small" type="primary" @click="handleAddUser"
>新增权限</el-button
>
</template>
</common-tools>
<!-- 表格 -->
<el-table border>
<el-table-column align="center" label="名称" />
<el-table-column align="center" label="标识" />
<el-table-column align="center" label="描述" />
<el-table-column align="center" label="操作">
<template>
<el-button type="text">添加</el-button>
<el-button type="text">编辑</el-button>
<el-button type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import CommonTools from '../../components/CommonTools'
export default {
components: {
CommonTools
}
}
</script>
新增权限路由
import Layout from '@/layout'
export default {
path: '/rights',
component: Layout,
children: [{
path: '',
component: () => import('@/views/permission/index'),
name: 'rights',
meta: {
title: '权限管理',
icon: 'rights'
}
}]
}
展示权限列表
<script>
import CommonTools from '../../components/CommonTools'
import {
getPermissionList } from '@/api/permisson'
export default {
components: {
CommonTools
},
data() {
return {
list: [],
formData: {
name: '', // 名称
code: '', // 标识
description: '', // 描述
type: '', // 类型 该类型 不需要显示 因为点击添加的时候已经知道类型了
pid: '', // 因为做的是树 需要知道添加到哪个节点下了
enVisible: '0' // 开启
},
showDialog: false
}
},
computed: {
showText() {
return this.formData.id ? '编辑' : '新增'
}
},
created() {
this.getPermissionList()
},
methods: {
async getPermissionList() {
this.list = await getPermissionList('list')
}
}
}
</script>
新建分配权限弹出层
// 给角色分配权限
export function assignPerm(roleId, data) {
return request({
url: `roles/${
roleId}/rights`,
method: 'put',
data
})
}
<el-dialog title="分配权限" :visible="showPermDialog" @close="btnPermCancel">
<!-- 权限是一颗树 -->
<!-- 将数据绑定到组件上 -->
<!-- check-strictly 如果为true 那表示父子勾选时 不互相关联 如果为false就互相关联 -->
<!-- id作为唯一标识 -->
<el-tree
ref="permTree"
:data="permData"
:props="defaultProps"
:show-checkbox="true"
:check-strictly="false"
:default-expand-all="true"
:default-checked-keys="selectCheck"
node-key="id"
/>
<!-- 确定 取消 -->
<el-row slot="footer" type="flex" justify="center">
<el-col :span="6">
<el-button type="primary" size="small" @click="btnPermOK">确定</el-button>
<el-button size="small" @click="btnPermCancel">取消</el-button>
</el-col>
</el-row>
</el-dialog>
showPermDialog: false, // 控制分配权限弹层的显示后者隐藏
defaultProps: {
label: 'name'
},
permData: [], // 专门用来接收权限数据 树形数据
selectCheck: [], // 定义一个数组来接收 已经选中的节点
roleId: null, // 用来记录分配角色的id
roleInfo: {
}, // 记录当前分配权限的角色
展示所有权限和角色当前的权限
import {
getPermissionList } from '@/api/permission'
methods: {
async assignPerm(id) {
// 根据id查询当前分配权限的角色对象
this.roleInfo = this.roleList.filter(item => {
return item.id === id
})[0]
const res = await getPermissionList('tree')
this.permData = res
// 获取当前角色拥有的所有权限
this.getThreeKeys(this.roleInfo, this.selectCheck)
this.showPermDialog = true
},
// 获取角色下的所有权限id
getThreeKeys(node, arr) {
if (!node.children) {
return arr.push(node.id)
}
node.children.forEach(item => {
this.getThreeKeys(item, arr)
})
},
btnPermCancel() {
this.showPermDialog = false
this.permData = []
this.selectCheck = []
},
}
分配权限获取选择后的数据传给后台即可。
权限受控主要是通过控制路由,我们把路由封装成静态路由和动态路由,然后登陆时根据后台返回的角色权限来决定那个路由展示,从而控制左侧菜单栏的展示。
主要思路:通过vuex存储起来后台返回的角色拥有权限所展示的路由然后通过router.addRoutes()动态添加到路由中实现。