权限管控
介绍
Teek 基于 RBAC
内置权限管控,RBAC
(Role Based Access Control)权限指的是基于角色的访问控制。
权限管控分为路由权限和页面权限,也成为粗粒度权限和细粒度权限。
角色权限
角色权限是一个数组,支持多个角色进行权限管控。
路由角色权限
在 路由 中介绍过路由的配置,而路由角色权限也在其中的配置项里,即 meta.roles
。
{
path: "role",
component: () => import("@/views/permission/rolePermission.vue"),
name: "RolePermission",
meta: {
title: "权限编辑",
roles: ["admin"],
},
},
当在路由配置了 meta.roles
,则告诉 Teek 这是一个角色权限的路由,Teek 会在加载路由之前,通过当前用户角色和路由配置的 meta.roles
进行对比筛选,如果当前路由的 meta.roles
不符合用户角色,则拒绝加载该路由。
用户角色在哪呢?
用户角色存储在 Pinia 里,在 src/pinia/stores/core/user.ts
里有一个 roles 属性,这就是存储当前用户的角色。
该文件有一个 getUserInfo
函数,当每次进入 Teek 时,Teek 触发该函数获取用户信息以及用户角色,再调用 setRoles(用户角色)
进行存储用户角色。
拿到 roles 后,在后续进行路由的加载时,根据路由的 meta.roles
进行对比筛选,从而进行路由的权限管控。
提示
getUserInfo
函数的用户信息、角色获取逻辑需要开发者根据个人需求进行修改。
页面角色权限
除了上面的用角色权限来管理路由,您也可以用角色权限来管理页面内的任何操作,如按钮级别。
如用户在 src/stores/user.ts
的 roles 是 ["admin"]
。
信息
使用页面角色权限,不需要在路由配置 meta.roles
。
组件形式
Role 组件已经进行全局注册,无需引入。
<template>
<Role :value="['admin']">
<p>只有 admin 可以查看</p>
</Role>
</template>
函数形式
引入 hasRole
函数,该函数封装 usePermission
组合式函数里。
<script>
import { usePermission } from "@/composables";
const { hasRole } = usePermission();
</script>
<template>
<p v-if="hasRole(['admin'])">只有 admin 可以查看</p>
</template>
自定义指令权限
自定义指令已经全局注册到 Teek,可以直接使用。
<template>
<p v-role="['admin']">只有 admin 可以查看</p>
</template>
缺点:指令方式不能动态修改权限,在页面渲染完成后就固定了。
而组件形式和函数形式可以通过传入一个响应式变量,然后通过修改该变量来实现动态修改权限。
场景
角色权限使用场景:
- 页面是否可见,可进入
- 按钮是否可见、可编辑
- 部分内容是否可见、可编辑
- ......
认证权限
认证权限是一个数组,支持多个认证进行权限管控,使用方式和角色权限一样。
页面认证权限
在 路由 中介绍过路由的配置,而认证权限也在其中的配置项里,即 meta.auths
。
{
path: "role",
component: () => import("@/views/permission/rolePermission.vue"),
name: "RolePermission",
meta: {
title: "权限编辑",
auths: ["btn_add"],
},
},
这是一个路由内的认证权限配置。
和角色权限类似,认证权限的 页面认证权限
和角色权限的页面角色权限功能基本一样,不同的是 页面认证权限
必须依赖与路由的 meta.auths
,它没有像角色信息一样在 Pinia 存储。
认证权限的出现纯粹是为页面的内容管控进行设计,它的粒度更为细致。
组件形式
Auth 组件已经进行全局注册。
<template>
<Auth value="btn_add">
<el-button type="success">拥有 'btn_add' 权限可见</el-button>
</Auth>
</template>
函数形式
需要引入 hasRole
函数,该函数封装在 hooks 的 usePermission 里。
<script>
import { usePermission } from "@/composables";
const { hasAuth } = usePermission();
</script>
<template>
<el-button type="success" :disabled="hasAuth('btn_add')">拥有 'btn_add' 权限可编辑</el-button>
</template>
自定义指令权限
自定义指令已经全局注册到 Teek,可以直接使用。
<template>
<el-button type="success" v-auth="['btn_add']">拥有 'btn_add' 权限可见</el-button>
</template>
缺点:指令方式不能动态修改权限,在页面渲染完成后就固定了。
而组件形式和函数形式可以通过传入一个响应式变量,然后通过修改该变量来实现动态修改权限。
场景
页面认证权限使用场景:
- 按钮是否可见、可编辑
- 部分内容是否可见、可编辑
- ......
官方形式
除了上面 Teek 内置的三大形式来判断角色权限或者认证权限,也可以使用最原始的形式:
const route = useRoute();
// 获取角色权限
route.meta.roles;
// 获取认证权限
route.meta.auths;
角色和认证区别
- 角色权限是一个 粗粒度 的权限管控,一般用于路由、菜单的权限管控(是否可进入)
- 认证权限是一个 细粒度 的权限管控,一般用于页面内的内容、按钮等 DOM 的权限管控(按钮是否可见、可编辑,部分内容是否可见)
认证权限提供了组件、函数、指令三大形式,其目的就是管控页面内的 DOM 元素。
角色权限也提供了组件、函数、指令三大形式,同样支持管控页面内的 DOM 元素,但是最初的角色权限仅仅是用于路由、菜单的权限管控,因为部分使用场景既要角色权限管控路由、菜单,也要管控页面内的 DOM 元素,所以就设计了和认证权限一样的组件、函数、指令三大形式,这样可以减少额外配置认证权限的重复性。
虽然角色认证功能涵盖了认证权限的场景,但是如果对权限这一块的设计非常精细,则建议分工明确,角色管理页面本身(路由访问)的权限,认证管理页面内容的权限,这样就不因为纯粹使用角色管控两块从而导致设计复杂,耦合性高。
当然如果是小型项目,则可以用角色来充当所有权限管控的基石。
数据权限
Teek 暂时不支持针对到某行数据的权限管控,这是一种更细粒度的权限管控,这往往是后台来进行管控。
如果前端要管控数据权限,则依然可以用认证权限来管控,不过可控性较低、稳定性较低、配置复杂度较高,根据项目的复杂度来决定。