1.这节我们先做操作,再来理清下原理,我们还是拿登录日志来做操作,我们的若依后台有两个登录账号admin和ry,默认admin是超级管理员,登录日志有个新建按钮,我们要实现用admin登录能看到新建按钮,而用ry登录,看不到新建按钮的效果。
2.由于之前我们设置了/list/loginfo不能在地址栏中直接输入访问,我们现在要用登录日志做示例,就要放开权限,我们到config/config.js中注销掉登录日志的路由中的 // access: ‘authorize’,这行,注释后的登录日志完整路由配置为
{name: 'loginfor',icon: 'smile',path: '/list/loginfo',component: './loginfo',// access: 'authorize',},
3.在src/utils目录下新建permission.js文件,完整的permission.js代码如下
export function matchPermission (permissions, value) {if(permissions === undefined)return false;const type = typeof value;if (type === 'string') {return matchPerm(permissions, value);}return matchPerms(permissions, value);}// /**// * 字符权限校验// * @param {Array} value 校验值// * @returns {Boolean}// */export function matchPerms (permissions, value) {if (value && value instanceof Array && value.length > 0) {const permissionDatas = value;const all_permission = '*:*:*';const hasPermission = permissions.some((permission) => {return all_permission === permission || permissionDatas.includes(permission);});if (!hasPermission) {return false;}return true;}console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`);return false;}export function matchPerm (permissions, value) {if (value && value.length > 0) {const permissionDatas = value;const all_permission = '*:*:*';const hasPermission = permissions.some((permission) => {return all_permission === permission || permissionDatas === permission;});if (!hasPermission) {return false;}return true;}console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`);return false;}/*** 角色权限校验* @param {Array} value 校验值* @returns {Boolean}*/export function checkRole (roles, value) {if (roles && value && value.length > 0) {for(let i = 0; i< roles?.length; i ++) {for(let j = 0; j< value?.length; j ++) {if(value[j] === roles[i].roleKey) {return true;}}}}console.error(`need roles! Like checkRole="['admin','editor']"`);return false;}
4.修改app.jsx中的fetchUserInfo代码,主要改下返回的结果,修改后的fetchUserInfo代码如下
const fetchUserInfo = async () => {try {const msg = await queryCurrentUser();const currentUser={...msg.user,permissions: msg.permissions};console.log("login user info:",currentUser);return currentUser;} catch (error) {history.push(loginPath);}return undefined;};
这里我们在fetchUserInfo中加入了, msg.permissions,也就是在全局初始数据的currentUser中会加入从后台拿到的当前用户的权限列表,超管的permissions是[‘::*’],ry的permissions是
['system:user:resetPwd','system:post:list','monitor:operlog:export','monitor:druid:list','system:menu:query','system:dept:remove','system:menu:list','tool:gen:edit','system:dict:edit',... //此处省略若干权限值]
这个permissions是个数组,代表当前登录用户有权操作的标识列表。超管的[‘::*’]代表啥都可以操作。
5.打开src/access.js,先引入第3步中权限判断的方法
import { matchPermission } from "./utils/permission";
6.在access.js的access 函数的return结果中增加一些代码。完整的access函数代码如下
export default function access(initialState) {const { currentUser, menuData } = initialState || {};return {hasPerms: (perm) => {return matchPermission(currentUser?.permissions, perm);},hasNoPerms: (perm) => {return !matchPermission(currentUser?.permissions, perm);},authorize: (route) => {if(menuData) {const items = getMatchMenuItem(route.path, menuData);if(!items || items.length === 0){return false;} else {return true;}}return true;}, // initialState 中包含了的路由才有权限访问};}
其中authorize是上次我们做路由和菜单权限控制时用的,这里我们加了两个key hasPerms,hasNoPerms从字面意义就可以判断hasPerms是判断是不是有权限,返回true为有权限,
hasNoPermss是判断没有权限,返回true为没有权限。
7.打开登录日志操作的列表页面src/pages/loginfo/index.jsx,我们要判定的新建按钮在这个jsx文件里面,先import一段代码,在页面开头最后一行的impor后新起一行,加一个import
import { useAccess } from 'umi';
8.在const TableList = () => { 函数中的,第一行加一行代码 const access = useAccess();
const TableList = () => {const access = useAccess();......
9.找到新建按钮的代码位置
toolBarRender={() => [<Buttontype="primary"key="primary"onClick={() => {handleModalVisible(true);}}><PlusOutlined /> 新建</Button>,]}
在Button上增加一行代码 hidden={access.hasNoPerms(‘system:loginfo:add’)}
toolBarRender={() => [<Buttontype="primary"key="primary"hidden={access.hasNoPerms('system:loginfo:add')}onClick={() => {handleModalVisible(true);}}><PlusOutlined /> 新建</Button>,]}
这里的system:loginfo:add是我们自定义的一个权限标识,标识对登录日志的新增权限,这个权限超管的permision中没有但是配置了[‘::*’],超管他是有权限的,而ry的permision列表里面肯定没有这个system:loginfo:add权限标识,所以这个按钮超管可见,而ry不可见。
10.保存前端代码,编译后先用admin登录,然后在地址栏中输入list/loginfo看是否能见到新建按钮,截图如下
11.切换ry用户登录,然后再地址栏中如如list/loginfo,看能否见到新建按钮,截图如下
通过当前的登录用户的权限列表值,permissions可以控制页面按钮级别的显示、隐藏,这个permission的值,我们在后台可以配置。这样就可以实现页面按钮级别的权限控制了。
12.做完操作,看到效果,我们再总结下原理,我们可以从后台获取到当前用户的permissions,将其写入全局初始数据currentUser中,然后在access.js中可以配置是否有权的key hasPerms或者hasNoPerms,传入一个当前的操作权限值如system:loginfo:add,根据currentUser中当前用户的权限列表permissions,我们可以判断当前用户是否有system:loginfo:add的操作权限,根据权限值真假,来控制按钮显示或者隐藏,permissions后台可配,另外如果要实现根据不同角色控制按钮的权限,原理类似。
