目录
一、菜单,按钮权限配置
二、根据不同角色配置不同的菜单权限以及按钮权限,具体页面显示如下
三、根据不同的权限显示不同的菜单
四、按钮显示隐藏
权限控制是项目中,特别是系统项目中比较常见的功能了。 那么我现在就来结合实际的项目需求,讲讲在react中是如何实现权限控制的。项目是使用umi搭建的,实现的需求有:
根据不同角色配置不同的菜单权限以及按钮权限
根据不同的权限显示不同的菜单
按钮显示隐藏
1.项目使用的是配置式路由,首先我们将config/routes.ts作为路由以及每个路由下的所有权限值配置的文件,该文件的具体配置如下:
export default [
{path:'/',
component:'',
routes:[
{
path:'/router1',
name:'菜单一',
icon:'icon1',
component:'./router1',
mxcAuth:[//按钮权限的配置
{
label: '新增',
value: 'auth_add',
},
{
label: '删除',
value: 'auth_delete',
}
{
label: '编辑',
value: 'auth_edit',
}]
}
]}
];
1.根据我们的配置文件和用户权限配置图可知按钮的权限多了一个菜单用来控制该菜单是否显示,那么我们需要将权限配置列表的数据经过如下处理转成我们所需的数据:
import routes from 'config/routes';
const recursionFormatMenu = (routes: any[]): MenuAuthDsItem[] => {
return routes.map((item) => {
const { path, name, mxcAuth, routes } = item;
const tempResult = {
path,
name,
mxcAuth:
mxcAuth && mxcAuth?.length
? [
{ label: '菜单', value: `${path}/auth_menu` },
...mxcAuth.map((authItem) => ({
label: authItem.label,
value: `${path}/${authItem.value}`,
})),
]
: [{ label: '菜单', value: `${path}/auth_menu` }],
};
if (routes) {
return {
...tempResult,
children: recursionFormatMenu(routes),
};
}
return tempResult;
});
};
const getMenuAuthDs = (routes: any[]): MenuAuthDsItem[] => {
const root = lodash.find(routes, { path: '/' })?.routes || []; // 只处理 path: '/', 下的路由
const target = lodash.filter(root, (item) => item.path && item.name && !item.isOpen); // 只保留有 path 并且有 name 的元素 并且不是开放页面的元素
return recursionFormatMenu(target);
}
const menuAuthDs: MenuAuthDsItem[] = useMemo(() => {
return getMenuAuthDs(routes);//权限设置列表渲染的数据
}, [routes]);
2.将权限配置列表经过上述处理转为如下数据,菜单的权限值被设置为/${path}/auth_menu,然后给对应的角色勾选对应的权限之后,将值传给后端:
{
path:'/router1',
name:'菜单一',
icon:'icon1',
component:'./router1',
mxcAuth:[//按钮权限的配置
{
label: '菜单',
value: '/menu1/auth_menu',
},
{
label: '新增',
value: '/menu1/auth_add',
},
{
label: '删除',
value: '/menu1/auth_delete',
},
{
label: '编辑',
value: '/menu1/auth_edit',
}]
}
1.用户登录成功之后,后端会把该账号对应的权限值返回回来,如返回authList:["/menu1/auth_menu","/menu1/auth_edit"],将该值存在全局状态中
2.获取有权限的菜单列表,getAuthMenu()
import routes from 'config/routes';
const checkAuthMenuData = (menuList: any[], mxcAuthList: string[]): any[] => {
return menuList
.map((item: any) => {
const { path, routes } = item;
if (!mxcAuthList.includes(`${path}/auth_menu`) && path !== '/') {
return null;
}
return {
...item,
routes: routes ? checkAuthMenuData(routes, mxcAuthList) : [],
};
})
.filter((item: any) => item);
};
const getAuthMenu = async (routes) => {
try {
const res = await dispatch({//从全局状态中获取该账户的权限值
type: 'global/getMenuList',
});
const { isAdmin = false, authList = [] } = res || {};
const realDefaultMenuData = routes.map((res: any) => {
return {
...res,
icon: res.isCustomIcon ? svgList[res.icon] : res.icon,
};
});
if (isAdmin) { //判断是否是管理员,如果是管理员则返回所有权限列表
return realDefaultMenuData;
}
const result = checkAuthMenuData(realDefaultMenuData, authList);
return result;
} catch (err) {}
}
我们将控制按钮显示隐藏的功能抽出为一个公共的组件,组件主要实现的功能是,我们只要传入某个按钮在权限列表下配置的权限值,组件会去查看该角色的是否有该按钮的权限值,有的话则显示对应的按钮,没有的话则显示空或者自定义内容显示。组件的封装如下:
import { useLocation } from 'umi';
export interface AccessProps {
auth: string; // 匹配的权限字符串
fallback?: React.ReactNode; // 无权限时的显示,默认无权限不显示任何内容
}
const Access: React.FC = (props) => {
const { auth, loading = false, fallback = null, spinProps = {}, children } = props;
const location = useLocation();
const { pathname } = location || {};
const mxcAuthList = useSelector((state: any) => state.global.authList);
const accessible = useMemo(() => {
return mxcAuthList.includes(`${pathname}/${auth}`);
}, [location, auth, mxcAuthList]);
return (
{ accessible ? (
children
) : (
fallback
)}
);
};
export default Access;
使用如下:
菜单一编辑按钮
以上就是最近关于权限控制的实践,做到对菜单和按钮进行鉴权。大致思路如上,上述演示的只有一级菜单,实际是支持多级菜单的,还有很多细节方面可以根据具体的项目进行优化。