Skip to content

权限

权限控制采用后端控制模式,通过后端返回的菜单数据进行统一管理。系统支持对菜单、路由和按钮等资源进行精细化的权限控制,确保安全性和可维护性。

原理与流程

系统的权限控制基于后端返回的菜单数据实现。具体流程如下:

  1. 用户登录成功后,系统会在路由守卫 router.beforeEach 中触发权限初始化
  2. 调用 getMenuData() 方法从后端获取该用户的权限菜单数据
  3. 获取到的原始菜单数据会经过 processRoute() 处理,转换成前端可用的路由格式
  4. 处理后的菜单数据会被存储到 Pinia store(useMenuStore)中,用于全局状态管理
  5. 最后通过 registerAsyncRoutes() 方法将菜单动态注册为路由

这种方式确保了用户只能访问其权限范围内的功能。如果用户没有某个菜单的权限,该菜单不会显示,相应的路由也不会被注册,从而从根本上防止了越权访问。整个流程做到了权限的动态加载和安全控制。

关键代码

开始获取菜单数据

ts
router.beforeEach(async (to, from, next) => {
  // ...
  await getMenuData()
  // ...
}

获取到菜单数据后,处理菜单数据,菜单数据存储到 Pinia store,动态注册路由

ts
async function getMenuData(): Promise<void> {
  // ...
  // 获取菜单列表
  const { menuList, closeLoading } = await menuService.getMenuList();
  // ...
  // 设置菜单列表
  useMenuStore().setMenuList(menuList as []);
  // 注册异步路由
  registerAsyncRoutes(router, menuList);
  // 关闭加载动画
  closeLoading();
  // ...
}

获取菜单数据

ts
// 菜单接口(模拟网络请求)
export const menuService = {
  getMenuList(
    delay: number = 300
  ): Promise<{ menuList: MenuListType[]; closeLoading: () => void }> {
    // menuList 是后端返回的菜单数据
    const menuList = asyncRoutes;
    // 处理返回的菜单数据
    const processedMenuList: MenuListType[] = menuList.map((route) =>
      processRoute(route)
    );
    // ...
  },
};

菜单权限

菜单权限通过 src/router/modules/asyncRoutes.ts 文件进行配置。系统会根据该文件中定义的路由配置或后端返回的菜单数据进行匹配 - 当菜单数据中包含对应的路由配置时,该菜单项会被显示在导航栏中,并且相应的路由会被动态注册到系统中。这种机制确保了用户只能看到和访问其拥有权限的菜单项。

代码示例

ts
{
  id: 3,
  path: '/menu',
  name: 'Menu',
  component: RoutesAlias.Home,
  meta: {
    title: 'menus.menu.title',
    icon: '&#xe8a4;',
    keepAlive: false
  },
  children: [
    {
      id: 401,
      path: 'menu',
      name: 'Menus',
      component: RoutesAlias.Menu,
      meta: {
        title: 'menus.menu.menu',
        icon: '&#xe8a4;',
        keepAlive: true
      }
    },
  ]
}

路由权限

路由权限是通过动态处理菜单数据实现的。系统会根据后端返回的菜单数据动态生成并注册路由配置。这确保了用户只能访问其权限范围内的路由 - 如果某个路由在菜单数据中不存在,则不会被注册,用户也就无法访问该路由。

// 静态路由(不需要权限)
// src/router/index.ts
const staticRoutes = [];

// 动态路由(需要权限)
// src/router/modules/asyncRoutes.ts
const asyncRoutes = [];

按钮权限

按钮权限通过配置菜单列表的 authList 来控制。每个菜单项的 authList 包含了该页面所有可用的按钮权限配置。当页面中使用 v-auth 指令的按钮,其值与 authList 中某个配置的 auth_mark 匹配时,该按钮才会显示。例如 v-auth="'add'" 将会匹配 auth_mark: 'add' 的权限配置。

自定义指令:

按钮权限通过自定义指令 v-auth 进行控制,该指令的具体实现在 src/directives/permission.ts 文件中。指令会根据当前页面菜单的 authList 配置来判断按钮是否有权限显示。

用法:

html
<el-button v-auth="'add'">新增</el-button>
<el-button v-auth="'edit'">编辑</el-button>
<el-button v-auth="'delete'">删除</el-button>
ts
{
  id: 3,
  path: '/menu',
  name: 'Menu',
  component: RoutesAlias.Home,
  meta: {
    title: 'menus.menu.title',
    icon: '&#xe8a4;',
    keepAlive: false
  },
  children: [
    {
      id: 401,
      path: 'menu',
      name: 'Menus',
      component: RoutesAlias.Menu,
      meta: {
        title: 'menus.menu.menu',
        icon: '&#xe8a4;',
        keepAlive: true,
        authList: [
          {
            id: 4011,
            title: '新增',
            auth_mark: 'add'
          },
          {
            id: 4012,
            title: '编辑',
            auth_mark: 'edit'
          },
          {
            id: 4013,
            title: '删除',
            auth_mark: 'delete'
          }
        ]
      }
    },
  ]
}

Released under the MIT License.