权限

项目中集成了三种权限处理方式:

  1. 通过用户角色来过滤菜单(前端方式控制),路由在前端配置,通过API返回角色过滤
  2. 通过后台来动态生成路由表(后台方式控制)
  3. 通过后台返回所有权限集合(包括菜单和按钮),前端固定路由,进行过滤

前端角色权限

实现原理: 在前端固定写死路由的权限,指定路由有哪些权限可以查看。只初始化通用的路由,需要权限才能访问的路由没有被加入路由表内。在登陆后或者其他方式获取用户角色后,通过角色去遍历路由表,获取该角色可以访问的路由表,生成路由表,再通过 router.addRoute 添加到路由实例,实现权限的过滤。

缺点: 权限相对不自由,如果后台改动角色,前台也需要跟着改动。适合角色较固定的系统

实现

在项目配置projectSetting.ts将系统内权限模式改为 ROLE 模式

  1. const setting: setting = {
  2. //菜单权限模式 FIXED 前端固定路由 BACK 动态获取
  3. permissionMode: 'FIXED',
  4. };

后台动态路由

实现原理: 在前端固定,路由表对应的组件映射map,通过API获取路由表,动态生成路由,再通过 router.addRoute 添加到路由实例,实现权限的过滤。

缺点: 前端需要维护一个路由表,保持和后端一致,如果后台改动角色,前台也需要跟着改动。

提示: 多级路由,当没有配置时,redirectredirect 默认为第一个子路由,配置则优先按配置

实现

  1. import { RouteRecordRaw } from 'vue-router';
  2. import { Layout } from '@/router/constant';
  3. import { DashboardOutlined } from '@vicons/antd';
  4. import { renderIcon } from '@/utils/index';
  5. const routeName = 'dashboard';
  6. const routes: Array<RouteRecordRaw> = [
  7. {
  8. path: '/dashboard',
  9. name: routeName,
  10. redirect: '/dashboard/console',
  11. component: Layout,
  12. meta: {
  13. title: 'Dashboard',
  14. icon: renderIcon(DashboardOutlined),
  15. //这里配置父级路由需要哪些权限可访问 这里是子路由权限集合
  16. permissions: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
  17. sort: 0,
  18. },
  19. children: [
  20. {
  21. path: 'console',
  22. name: `${routeName}_console`,
  23. meta: {
  24. title: '主控台',
  25. //配置该路由需要哪些权限可访问 这里是针对单个路由
  26. permissions: ['dashboard_console'],
  27. },
  28. component: () => import('@/views/dashboard/console/console.vue'),
  29. },
  30. ],
  31. },
  32. ];
  33. export default routes;

::: warning 注意

后端接口返回的数据结构请参考,/mock/user/menu.ts menusList

:::

通过所有权限

实现原理: 在前端固定路由表,并且配置路由所需的权限,实现权限的过滤。

缺点: 权限过多,不易维护,毕竟权限集合不在前端定义

优点: 简单,实用,菜单,按钮,等所有权限都可以通吃

实现

  1. import { RouteRecordRaw } from 'vue-router';
  2. import { Layout } from '@/router/constant';
  3. import { DashboardOutlined } from '@vicons/antd';
  4. import { renderIcon } from '@/utils/index';
  5. const routeName = 'dashboard';
  6. const routes: Array<RouteRecordRaw> = [
  7. {
  8. path: '/dashboard',
  9. name: routeName,
  10. redirect: '/dashboard/console',
  11. component: Layout,
  12. meta: {
  13. title: 'Dashboard',
  14. icon: renderIcon(DashboardOutlined),
  15. //这里配置父级路由需要哪些权限可访问 这里是子路由权限集合
  16. permissions: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
  17. sort: 0,
  18. },
  19. children: [
  20. {
  21. path: 'console',
  22. name: `${routeName}_console`,
  23. meta: {
  24. title: '主控台',
  25. //配置该路由需要哪些权限可访问 这里是针对单个路由
  26. permissions: ['dashboard_console'],
  27. },
  28. component: () => import('@/views/dashboard/console/console.vue'),
  29. },
  30. ],
  31. },
  32. ];
  33. export default routes;

细粒度权限

函数方式

usePermissions 还提供了按钮级别的权限控制。

  1. <template>
  2. <n-button v-if="haspermissions([RoleEnum.ADMIN, RoleEnum.NORMAL])">
  3. 拥有[admin,normal]权限可见
  4. </n-button>
  5. </template>
  6. <script lang="ts">
  7. import { usepermissions } from '@/hooks/web/usepermissions';
  8. import { RoleEnum } from '@/enums/roleEnum';
  9. export default defineComponent({
  10. setup() {
  11. const { haspermissions } = usepermissions();
  12. return { haspermissions, RoleEnum };
  13. },
  14. });
  15. </script>

指令方式

::: tip

指令方式不能动态更改权限

:::

  1. @param seffect 'disabled' 禁用按钮 不传 默认移除按钮
  2. <n-button v-permissions="{action:['RoleEnum.ADMIN, RoleEnum.NORMAL'], effect:'disabled'}" type="primary" class="mx-4"> 拥有admin,normal角色权限可见</n-button>