ant-design-pro 4.x 权限控制剖析
ant-design-pro 5.0 发布之际,把 4.x 的权限控制原理梳理了一遍。
第一部分,页面加载,生成控制权限的组件 Authorized (@/utils/Authorized.ts),获取当前权限。
1. 程序一加载,传递 getAuthority() 返回的 currentAuthority,调用 RenderAuthorize 函数,返回 Authorized 权限控制组件(返回值说明见第二步)
// src/utils/Authorized.ts
import RenderAuthorize from '@/components/Authorized';
import { getAuthority } from './authority';
let Authorized = RenderAuthorize(getAuthority());
2. 第一步中 引入的 RenderAuthorize 为一个函数, 接收当前权限,currentAuthority 作为参数,返回 Authorized 权限控制组件; 因此,上一步中,let Authorized = RenderAuthorize(getAuthority()); 变量 Authorized 即为 src/components/Authorized/Authorized.ts 组件,同时 通过调用 RenderAuthorize,对 当前权限 CURRENT 做了更新。
// src/components/Authorized/index.ts
import Authorized from './Authorized'; // 控制权限的包裹组件
...
import renderAuthorize from './renderAuthorize';
...
const RenderAuthorize = renderAuthorize(Authorized); // 根据下面的代码可知,renderAuthorize(Authorized) 的调用结果为一个函数
export default RenderAuthorize;
------------------------------------------------------------------------
// src/components/Authorized/renderAuthorize.ts
let CURRENT: string | string[] = 'NULL';
const renderAuthorize = (Authorized) => (
currentAuthority: CurrentAuthorityType,
) => {
if (currentAuthority) {
...
} else {
CURRENT = 'NULL';
}
return Authorized;
};
export default <T>(Authorized: T) => renderAuthorize<T>(Authorized);
第二部分,根据权限展示或隐藏菜单。
1. 通过 BasicLayout 的 menuDataRender 属性, 控制菜单是否显示。
Authorized.check 校验路由的权限,authority 是否有至少一项包含在当前用户权限 currentAuthority 中。返回传入路由,或 null。
// src/layouts/BasicLayout.ts
const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] => {
return menuList.map((item) => {
const localItem = {
...item,
children: item.children ? menuDataRender(item.children) : undefined,
};
return Authorized.check(item.authority, localItem, null) as MenuDataItem;
});
};
2. 调用 check 函数,就是调用 checkPermissions 函数,第二个参数为第一部分中,附上值的 CURRENT。
// src/components/Authorized/CheckPermissions.tsx
import { CURRENT } from './renderAuthorize';
const checkPermissions = <T, K>(
authority: IAuthorityType,
currentAuthority: string | string[],
target: T,
Exception: K,
): T | K | React.ReactNode => {
// 没有判定权限.默认查看所有
// Retirement authority, return target;
if (!authority) {
return target;
}
// 数组处理
if (Array.isArray(authority)) {
if (Array.isArray(currentAuthority)) {
if (currentAuthority.some((item) => authority.includes(item))) {
return target;
}
} else if (authority.includes(currentAuthority)) {
return target;
}
return Exception;
}
...
throw new Error('unsupported parameters');
};
function check(authority: IAuthorityType, target: T, Exception: K): T | K | React.ReactNode {
return checkPermissions<T, K>(authority, CURRENT, target, Exception);
}
第三部分,路由权限控制。
1. 获取跟 pathname 匹配的路由
// src/utils/utils.ts
// 返回跟 pathname 匹配的路由
export const getAuthorityFromRouter = <T extends Route>(
router: T[] = [],
pathname: string,
): T | undefined => {
const authority = router.find(
({ routes, path = '/', target = '_self' }) =>
(path && target !== '_blank' && pathRegexp(path).exec(pathname)) ||
(routes && getAuthorityFromRouter(routes, pathname)),
);
if (authority) return authority;
return undefined;
};
2. 获取当前 url 匹配的路由后,传入该路由的 authority,通过 Authorized 组件包裹 children 校验权限。
// src/layouts/BasicLayout.tsx
import { getAuthorityFromRouter } from '@/utils/utils';
const BasicLayout = () => {
...
const authorized = getAuthorityFromRouter(props.route.routes,
location.pathname || '/') || {
authority: undefined,
};
return (
<ProLayout>
...
<Authorized authority={authorized!.authority} noMatch={noMatch}>
{children}
</Authorized>
</ProLayout>
);
};
3. Authorized 组件内部,也通过 check 函数校验权限
// src/components/Authorized/Authorized.tsx
import check, { IAuthorityType } from './CheckPermissions';
const Authorized: React.FunctionComponent<AuthorizedProps> = ({
children,
authority,
noMatch = (
<Result
status="403"
title="403"
subTitle="Sorry, you are not authorized to access this page."
/>
),
}) => {
const childrenRender: React.ReactNode = typeof children === 'undefined' ? null : children;
const dom = check(authority, childrenRender, noMatch);
return <>{dom}</>;
};
export default Authorized as IAuthorizedType;

浙公网安备 33010602011771号