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={() => [
<Button
type="primary"
key="primary"
onClick={() => {
handleModalVisible(true);
}}
>
<PlusOutlined /> 新建
</Button>,
]}
在Button上增加一行代码 hidden={access.hasNoPerms(‘system:loginfo:add’)}
toolBarRender={() => [
<Button
type="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后台可配,另外如果要实现根据不同角色控制按钮的权限,原理类似。