如何实现权限控制时一级菜单跳转有权限的任意二级菜单

后台系统中使用模块较多时,一般都会通过一级菜单二级菜单来组织模块,并且使用面包屑导航。一般一级菜单通常都是作为模块导航和入口,跳转到第一个二级菜单。 如果按照上篇文章实现了权限控制之后,就需要根据当前用户拥有的权限判断一级菜单跳转到那个二级菜单下。

本文介绍如何实现权限控制时一级菜单跳转有权限的任意二级菜单。

实现方式

1. 当前路由配置

typescript 复制代码
export const routes = [
  {
    path: '/list',
    icon: 'smile',
    routes: [
      {
        path: '/list/table-list',
        component: './TableList',
        access: 'canAccessRoute',
        meta: {
          permission: PERMISSIONS.LIST.TABLE_LIST.READ,
        },
      },
      {
        path: '/list/basic-list',
        component: './BasicList',
        access: 'canAccessRoute',
        meta: {
          permission: PERMISSIONS.LIST.BASIC_LIST.READ,
        },
      },
    ]
  },
];

2. 修改后的路由配置

首先先给一级路由加上权限控制,并且记录下该一级菜单拥有的所有二级菜单权限标记,后面可以通过路由信息中获取到进行匹配。

typescript 复制代码
export const routes = [
  {
    path: '/list',
    icon: 'smile',
    access: 'canAccessRoute', // 加上权限控制一级菜单
    meta: {
      permissions: [ // 加上该一级菜单下的二级菜单权限标记
        PERMISSIONS.LIST.TABLE_LIST.READ, 
        PERMISSIONS.LIST.BASIC_LIST.READ
      ],
    },
    routes: [
     // ...
    ]
  },
];

在权限判断逻辑中加上一级菜单判断有任意子路由即拥有菜单权限

typescript 复制代码
export default function access(initialState) {
  const { userPermissions } = initialState ?? {};

  function canAccessRoute(route: IRoute) {
    // 一级菜单判断有任意子路由即拥有菜单权限
    if (route.meta?.permissions) {
      return route.meta?.permissions.some((permission: string) =>
        menu_permissions.includes(permission),
      );
    }
  
    // 页面对应的权限标记,需要在当前用户拥有的权限中
    if (route.meta?.permission) {
      return userPermissions.includes(route.meta.permission);
    }
    // 无页面权限标记说明改页面不需要权限也能访问
    return true;
  }

  return {
    canAccessRoute,
  };
}

3. 实现一级菜单跳转有权限的任意二级菜单组件

这里使用 UmiJs - 路由 wrappers 配置路由组件的包装组件,可以直接实现路由跳转的功能。 其他框架也可以直接实现一个类似的 HOC 包裹后的页面也可以实现一样的功能。

tsx 复制代码
type RedirectRouteType = {
  permission: string;
  path: string;
};

const redirectRoutesMap: Record<string, RedirectRouteType[]> = {
  '/list': [
    {
      permission: PERMISSIONS.LIST.TABLE_LIST.READ,
      path: '/list/table-list',
    },
    {
      permission: PERMISSIONS.LIST.BASIC_LIST.READ,
      path: '/list/basic-list',
    },
  ],
  '/module': [
    // ...
  ]
};

/**
 * 跳转到拥有权限的第一个子路由
 */
export default () => {
  const { initialState } = useModel('@@initialState');
  const { userPermissions } = initialState || {};

  const { route } = useRouteData(); // 获取出路由信息
  const redirectRoutes = redirectRoutesMap[route.path as string]; // 使用路由地址匹配出是哪个一级菜单

  // 找到当前一级菜单下有权限的第一个二级菜单地址
  const redirectTo = useMemo(() => {
    const matched = redirectRoutes.find((item) =>
      userPermissions.some((permission) => item.permission === permission),
    );
    const redirectPath = matched?.path || '/';
    return redirectPath;
  }, [redirectRoutes, userPermissions]);
  
  // 使用 Navigate 跳转到匹配到的那个二级菜单地址 
  return <Navigate to={redirectTo} />;
};

其他方案

以上实现的是跳转点击是的路由判断后进行跳转。这里也提供另一个实现的方案,可供参考。可以借助动态路由相关的 API,当获取用户权限之后,根据获取的用户权限生成用户拥有的所有路由,并且将这些动态路由加入路由配置中,这样用户就不拥有不存在权限路由,也可以实现该功能。

参考链接

相关推荐
傻小胖16 分钟前
React 脚手架配置代理完整指南
前端·react.js·前端框架
EterNity_TiMe_28 分钟前
【论文复现】农作物病害分类(Web端实现)
前端·人工智能·python·机器学习·分类·数据挖掘
余生H1 小时前
深入理解HTML页面加载解析和渲染过程(一)
前端·html·渲染
吴敬悦1 小时前
领导:按规范提交代码conventionalcommit
前端·程序员·前端工程化
ganlanA1 小时前
uniapp+vue 前端防多次点击表单,防误触多次请求方法。
前端·vue.js·uni-app
卓大胖_1 小时前
Next.js 新手容易犯的错误 _ 性能优化与安全实践(6)
前端·javascript·安全
m0_748246351 小时前
Spring Web MVC:功能端点(Functional Endpoints)
前端·spring·mvc
SomeB1oody1 小时前
【Rust自学】6.4. 简单的控制流-if let
开发语言·前端·rust
云只上1 小时前
前端项目 node_modules依赖报错解决记录
前端·npm·node.js
程序员_三木2 小时前
在 Vue3 项目中安装和配置 Three.js
前端·javascript·vue.js·webgl·three.js