Skip to content

权限

框架内置了两种权限控制方式:

  • 通过用户角色来判断菜单或者按钮是否可以访问
  • 通过接口来判断菜单或者按钮是否可以访问

前端访问控制

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

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

步骤

  • 确保当前模式为前端访问控制模式

调整对应应用目录下的preferences.ts,确保accessMode='frontend'

ts
import { defineOverridesPreferences } from '@vben/preferences';

export const overridesPreferences = defineOverridesPreferences({
  // overrides
  app: {
    // 默认值,可不填
    accessMode: 'frontend',
  },
});
  • 配置路由权限

如果不配置,默认可见

ts
 {
    meta: {
      authority: ['super'],
    },
},
  • 确保接口返回的角色和路由表的权限匹配

可查看应用下的 src/store/auth,找到下面代码,

ts
// 设置登录用户信息,需要确保 userInfo.roles 是一个数组,且包含路由表中的权限
// 例如:userInfo.roles=['super', 'admin']
authStore.setUserInfo(userInfo);

到这里,就已经配置完成,你需要确保登录后,接口返回的角色和路由表的权限匹配,否则无法访问。

菜单可见,但禁止访问

有时候,我们需要菜单可见,但是禁止访问,可以通过下面的方式实现,设置 menuVisibleWithForbiddentrue,此时菜单可见,但是禁止访问,会跳转403页面。

ts
{
    meta: {
      menuVisibleWithForbidden: true,
    },
},

后端访问控制

实现原理: 是通过接口动态生成路由表,且遵循一定的数据结构返回。前端根据需要处理该数据为可识别的结构,再通过 router.addRoute 添加到路由实例,实现权限的动态生成。

缺点: 后端需要提供符合规范的数据结构,前端需要处理数据结构,适合权限较为复杂的系统。

步骤

  • 确保当前模式为后端访问控制模式

调整对应应用目录下的preferences.ts,确保accessMode='backend'

ts
import { defineOverridesPreferences } from '@vben/preferences';

export const overridesPreferences = defineOverridesPreferences({
  // overrides
  app: {
    accessMode: 'backend',
  },
});
  • 确保接口返回的菜单数据结构正确

可查看应用下的 src/router/access.ts,找到下面代码,

ts
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
  return await generateAccessible(preferences.app.accessMode, {
    fetchMenuListAsync: async () => {
      // 这个接口为后端返回的菜单数据
      return await getAllMenus();
    },
  });
}
  • 接口返回菜单数据,可看注释说明
接口返回菜单数据示例
ts
const dashboardMenus = [
  {
    // 这里固定写死 BasicLayout,不可更改
    component: 'BasicLayout',
    meta: {
      order: -1,
      title: 'page.dashboard.title',
    },
    name: 'Dashboard',
    path: '/',
    redirect: '/analytics',
    children: [
      {
        name: 'Analytics',
        path: '/analytics',
        // 这里为页面的路径,需要去掉 views/ 和 .vue
        component: '/dashboard/analytics/index',
        meta: {
          affixTab: true,
          title: 'page.dashboard.analytics',
        },
      },
      {
        name: 'Workspace',
        path: '/workspace',
        component: '/dashboard/workspace/index',
        meta: {
          title: 'page.dashboard.workspace',
        },
      },
    ],
  },
];

到这里,就已经配置完成,你需要确保登录后,接口返回的菜单格式正确,否则无法访问。

按钮细粒度控制

在某些情况下,我们需要对按钮进行细粒度的控制,我们可以借助接口或者角色来控制按钮的显示。

权限码

权限码为接口返回的权限码,通过权限码来判断按钮是否显示,逻辑在src/store/auth下:

ts
const [fetchUserInfoResult, accessCodes] = await Promise.all([
  fetchUserInfo(),
  getAccessCodes(),
]);

userInfo = fetchUserInfoResult;
authStore.setUserInfo(userInfo);
accessStore.setAccessCodes(accessCodes);

找到 getAccessCodes 对应的接口,可根据业务逻辑进行调整。

权限码返回的数据结构为字符串数组,例如:['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']

有了权限码,就可以使用 @vben/access 提供的AccessControl组件及API来进行按钮的显示与隐藏。

组件方式

vue
<script lang="ts" setup>
import { AccessControl, useAccess } from '@vben/access';

const { accessMode, hasAccessByCodes } = useAccess();
</script>

<template>
  <!-- 需要指明 type="code" -->
  <AccessControl :codes="['AC_100100']" type="code">
    <Button> Super 账号可见 ["AC_1000001"] </Button>
  </AccessControl>
  <AccessControl :codes="['AC_100030']" type="code">
    <Button> Admin 账号可见 ["AC_100010"] </Button>
  </AccessControl>
  <AccessControl :codes="['AC_1000001']" type="code">
    <Button> User 账号可见 ["AC_1000001"] </Button>
  </AccessControl>
  <AccessControl :codes="['AC_100100', 'AC_100010']" type="code">
    <Button> Super & Admin 账号可见 ["AC_100100","AC_1000001"] </Button>
  </AccessControl>
</template>

API方式

vue
<script lang="ts" setup>
import { AccessControl, useAccess } from '@vben/access';

const { hasAccessByCodes } = useAccess();
</script>

<template>
  <Button v-if="hasAccessByCodes(['AC_100100'])">
    Super 账号可见 ["AC_1000001"]
  </Button>
  <Button v-if="hasAccessByCodes(['AC_100030'])">
    Admin 账号可见 ["AC_100010"]
  </Button>
  <Button v-if="hasAccessByCodes(['AC_1000001'])">
    User 账号可见 ["AC_1000001"]
  </Button>
  <Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])">
    Super & Admin 账号可见 ["AC_100100","AC_1000001"]
  </Button>
</template>

指令方式

指令支持绑定单个或多个权限码。单个时可以直接传入字符串或数组中包含一个权限码,多个权限码则传入数组。

vue
<template>
  <Button class="mr-4" v-access:code="'AC_100100'">
    Super 账号可见 'AC_100100'
  </Button>
  <Button class="mr-4" v-access:code="['AC_100030']">
    Admin 账号可见 ["AC_100010"]
  </Button>
  <Button class="mr-4" v-access:code="['AC_1000001']">
    User 账号可见 ["AC_1000001"]
  </Button>
  <Button class="mr-4" v-access:code="['AC_100100', 'AC_1000001']">
    Super & Admin 账号可见 ["AC_100100","AC_1000001"]
  </Button>
</template>

角色

角色判断方式不需要接口返回的权限码,直接通过角色来判断按钮是否显示。

组件方式

vue
<script lang="ts" setup>
import { AccessControl } from '@vben/access';
</script>

<template>
  <AccessControl :codes="['super']">
    <Button> Super 角色可见 </Button>
  </AccessControl>
  <AccessControl :codes="['admin']">
    <Button> Admin 角色可见 </Button>
  </AccessControl>
  <AccessControl :codes="['user']">
    <Button> User 角色可见 </Button>
  </AccessControl>
  <AccessControl :codes="['super', 'admin']">
    <Button> Super & Admin 角色可见 </Button>
  </AccessControl>
</template>

API方式

vue
<script lang="ts" setup>
import { useAccess } from '@vben/access';

const { hasAccessByRoles } = useAccess();
</script>

<template>
  <Button v-if="hasAccessByRoles(['super'])"> Super 账号可见 </Button>
  <Button v-if="hasAccessByRoles(['admin'])"> Admin 账号可见 </Button>
  <Button v-if="hasAccessByRoles(['user'])"> User 账号可见 </Button>
  <Button v-if="hasAccessByRoles(['super', 'admin'])">
    Super & Admin 账号可见
  </Button>
</template>

指令方式

指令支持绑定单个或多个权限码。单个时可以直接传入字符串或数组中包含一个权限码,多个权限码则传入数组。

vue
<template>
  <Button class="mr-4" v-access:role="'super'"> Super 角色可见 </Button>
  <Button class="mr-4" v-access:role="['super']"> Super 角色可见 </Button>
  <Button class="mr-4" v-access:role="['admin']"> Admin 角色可见 </Button>
  <Button class="mr-4" v-access:role="['user']"> User 角色可见 </Button>
  <Button class="mr-4" v-access:role="['super', 'admin']">
    Super & Admin 角色可见
  </Button>
</template>

贡献者

The avatar of contributor named as vben vben
The avatar of contributor named as handsomeFu handsomeFu
The avatar of contributor named as zyy zyy
The avatar of contributor named as vince vince

页面历史

基于 MIT 许可发布.