GGbond : react-router权限与父节点权限不匹配解决方案

51 阅读2分钟

今天在公司写代码的时候遇到一个问题

image.png 正常来说我给路由配置权限 ,只需要去 routerPerssion.ts文件中配置好路径,与对应后端返回的角色标识匹配上就能实现权限的操作 image.png image.png

问题

在配置后发现页面有问题 ,第一级路由 "消防管理" 的 element 属性定义了重定向到第二级路由 "消防日检" 的路径 PageUrl.FPM。这意味着当用户访问 "/消防管理" 时,他们将被重定向到 "/消防日检" 页面, 然后"/消防日检"他本身也是没有页面的,他会继续重定向到"/检查计划" ,如果此时用户没有"/检查计划"的权限,但是有日检和管理的权限的话 , 用户访问"/检查计划"会返回到上级菜单路径,上级菜单路径又重定向到了检查计划页面, 导致重复循环

image.png

解决方法 :

检查重定向部分

  1. 需要验证该路由是否包含了用户所具备的权限之一,如果不包含,则将该路由从菜单中隐藏,并设置 hasAuthority 属性为 false,表示该路由无权访问;
  2. 如果该路由存在子路由 item.routes,则递归遍历子路由进行相同的检查;
  3. 最后,检查父级路由是否重定向到 hasAuthority 为 false 的子路由上,如果是,则将其重定向到第一个 hasAuthority 不为 false 的子路由,如果没有,则重定向到 404 页面。
 /**
 * @desc 给路由模块注入权限
 */
const applyRouterPerssion = (permission: string[], roles: AccountRoleType[] = []) => {
  return new Promise<void>((resolve, _) => {
    function traverse(routes: PageRoute[], parent?: PageRoute) {
      for (let index = 0; index < routes.length; index++) {
        const item = routes[index];
        const routePath = item.path as string;

        if (routePath === '/') continue;
        if (!item.element && (item.routes ?? []).length < 1) continue;
        if (Object.prototype.hasOwnProperty.call(RouterPerssion, routePath) === false) continue;

        // 系统默认角色账户[ADMIN],默认具备所有权限
        if (roles.includes('ADMIN')) {
          routes[index].hideInMenu = undefined;
          routes[index].hasAuthority = undefined;
          continue;
        }

        // 至少需要包含一个需要的权限
        let needPerssion = (RouterPerssion as any)[routePath] as string[];

        if (needPerssion.some((key) => permission.includes(key)) === false) {
          routes[index].hideInMenu = true;
          routes[index].hasAuthority = false;
        }

        if (item.routes && item.routes.length > 0) traverse(item.routes, item);
      }

      // 检查父级重定向  
      if (parent) {
        let element = parent.element as React.ReactElement;
        let child = routes.find((o) => o.path === element?.props.to);

        if (child && child.hasAuthority === false) {
          let _list = routes.filter((o) => o.hasAuthority !== false);

          if (_list.length && _list[0].path) {
            parent.element = <Navigate replace to={_list[0].path} />;
          } else {
            parent.element = <Navigate replace to="404" />;
          }
        }
      }
    }

    traverse(basicRouter);
    traverse(blankRouter);
    resolve();
  });
};