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

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

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

实现方式

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,当获取用户权限之后,根据获取的用户权限生成用户拥有的所有路由,并且将这些动态路由加入路由配置中,这样用户就不拥有不存在权限路由,也可以实现该功能。

参考链接

相关推荐
甜兒.38 分钟前
鸿蒙小技巧
前端·华为·typescript·harmonyos
Jiaberrr4 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy5 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白5 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、5 小时前
Web Worker 简单使用
前端
web_learning_3215 小时前
信息收集常用指令
前端·搜索引擎
tabzzz5 小时前
Webpack 概念速通:从入门到掌握构建工具的精髓
前端·webpack
200不是二百5 小时前
Vuex详解
前端·javascript·vue.js
滔滔不绝tao5 小时前
自动化测试常用函数
前端·css·html5
码爸5 小时前
flink doris批量sink
java·前端·flink