权限

# 权限

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

1、通过用户角色来过滤菜单(前端方式控制),路由在前端配置,通过API返回角色过滤

2、通过后台来动态生成路由表(后台方式控制)

3、通过后台返回所有权限集合(包括菜单和按钮),前端固定路由,进行过滤


# 权限测试

项目菜单权限-FIXED模式 随机(普通管理员/超级管理员)角色权限示例

项目菜单权限-BACK模式随机(普通管理员/超级管理员)角色权限示例

说明超级管理员拥有 主控台列表页面 权限,普通管理员拥有 主控台 权限

测试退出登录>重新登录 或者刷新页面>查看效果


# 前端固定路由

# 实现原理

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


# 缺点

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


# 实现

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


# 后端动态路由

# 实现原理

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


# 缺点

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


# 提示

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


# 实现

import { RouteRecordRaw } from 'vue-router';
import { Layout } from '@/router/constant';
import { DashboardOutlined } from '@vicons/antd';
import { renderIcon } from '@/utils/index';

const routeName = 'dashboard';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/dashboard',
    name: routeName,
    redirect: '/dashboard/console',
    component: Layout,
    meta: {
      title: 'Dashboard',
      icon: renderIcon(DashboardOutlined),
      //这里配置父级路由需要哪些权限可访问 这里是子路由权限集合
      permissions: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
      sort: 0,
    },
    children: [
      {
        path: 'console',
        name: `${ routeName }_console`,
        meta: {
          title: '主控台',
          //配置该路由需要哪些权限可访问 这里是针对单个路由
          permissions: ['dashboard_console'],
        },
        component: () => import('@/views/dashboard/console/console.vue'),
      },
    ],
  },
];
export default routes;


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


# 通过所有权限

# 实现原理

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


# 缺点

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


# 优点

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

import { RouteRecordRaw } from 'vue-router';
import { Layout } from '@/router/constant';
import { DashboardOutlined } from '@vicons/antd';
import { renderIcon } from '@/utils/index';

const routeName = 'dashboard';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/dashboard',
    name: routeName,
    redirect: '/dashboard/console',
    component: Layout,
    meta: {
      title: 'Dashboard',
      icon: renderIcon(DashboardOutlined),
      //这里配置父级路由需要哪些权限可访问 这里是子路由权限集合
      permissions: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
      sort: 0,
    },
    children: [
      {
        path: 'console',
        name: `${ routeName }_console`,
        meta: {
          title: '主控台',
          //配置该路由需要哪些权限可访问 这里是针对单个路由
          permissions: ['dashboard_console'],
        },
        component: () => import('@/views/dashboard/console/console.vue'),
      },
    ],
  },
];
export default routes;


# 细粒度权限

# 函数方式

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

<template>
  <n-button v-if="hasPermissions([RoleEnum.ADMIN, RoleEnum.NORMAL])">
    拥有[admin,normal]权限可见
  </n-button>
</template>
<script lang="ts">
  import { usePermissions } from '@/hooks/web/usePermissions';
  import { RoleEnum } from '@/enums/roleEnum';

  export default defineComponent({
    setup() {
      const { hasPermissions } = usePermissions();

      return { hasPermissions, RoleEnum };
    },
  });
</script>


# 指令方式

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