前言
要弄清楚这个问题,我们先来看看什么是权限?个人认为,权限就是一系列用户可用的系统资源的整合,可以大致分为以下三类:
- 菜单权限:用户使用的菜单、查看的页面等。
- 操作权限:系统页面中的交互功能按钮,如编辑,删除,新增等。
- 数据权限:用户在页面中查看的数据内容,业务系统数据一般存在机密性,不同身份的用户查看的数据范围也有所不同。
了解了权限 ,那么 权限管理 也就比较清晰了,其实就是对系统用户访问资源的管理。根据业务要求的不同,用户看到的菜单、使用的功能、查看的数据都有所不同。
那么为什么要控制访问权限呢?因为不同的用户所负责的业务范围是不同的,比如管理者可以看到所有下属的信息,但是普通只能看到自己的;比如行政可以看到所有人的打卡记录,而普通员工只能看自己的;比如财务可以看到所有人的工资,而普通员工只能看到自己的....等等等等,
这都离不开 权限管理,通过为系统用户分配不同的权限,以达到精准控制的目的。
权限关系
1.角色和人员: 一个角色可以包含但不限于一个成员,一个成员可以被分配至多个权限角色中(取和值,即取多个角色权限的和值)
2.角色和菜单: 多对多关系:一个角色有多个菜单,一个菜单可以分配给多个角色
3.角色和权限资源管理: 多对多关系:一个角色有多个权限资源,一个权限资源可以分配给多个角色
思路跟方案
1.当用户开始访问
2.用户登录成功(并且拉取权限接口)
3.降权限数据保存到session中
4.根据获取的权限,对当前的路由进行序列化,不在该用户权限内的菜单排除序列化
5.文件目录和结构
css
├── src
├── api
└── sys.rbac.service.js
├── directive
├── directives.js
└── index.js
├── layout
├── components/Sidebar
└── index.js
├── router
└── index.js
├── store
├── modules
└── permission.js
└── getters.js
├── main.js
└── permission.js
序列化代码如下
permission.js
const component = modules[`你的组件路径`]?.default;
const route = {
path: path,
name: path + item.name,
meta: {
title: item.name,
svgIcon: 'dashboard',
affix: false,
},
};
路由js(router.js),异步加入路由菜单信息
js
permissionStore.dynamicRoutes.forEach((route: any) => {
router.addRoute(route);
});
permission指令注册
js
/** 权限指令,和权限判断函数 checkPermission 功能类似 */
export const permission: Directive = {
mounted(el, binding) {
const { value: permissionRoles } = binding;
const { roles } = useUserStoreHook();
if (Array.isArray(permissionRoles) && permissionRoles.length > 0) {
const hasPermission = roles.some((role) => permissionRoles.includes(role));
// hasPermission || (el.style.display = "none") // 隐藏
hasPermission || el.parentNode?.removeChild(el); // 销毁
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`);
}
},
};
使用办法
js
<el-button
v-permission="['TRAINING:PLAN:UPDATE@PUT']"
type="primary"
>编辑</el-button
>
加入路由白名单
whiteList.js
import { type RouteLocationNormalized } from 'vue-router';
/** 免登录白名单(匹配路由 path) */
const whiteListByPath: string[] = ['/login'];
/** 免登录白名单(匹配路由 name) */
const whiteListByName: string[] = [];
/** 判断是否在白名单 */
const isWhiteList = (to: RouteLocationNormalized) => {
// path 和 name 任意一个匹配上即可
return whiteListByPath.indexOf(to.path) !== -1 || whiteListByName.indexOf(to.name as any) !== -1;
};
export default isWhiteList;