拓冰建站拓冰建站
首页 / 资讯中心 / 正文

vue-vben-admin 权限访问控制完全指南:前端/后端/混合三种模式与按钮级细粒度权限实战

vue-vben-admin 权限访问控制完全指南前端/后端/混合三种模式与按钮级细粒度权限实战【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-adminvue-vben-admin 内置了基于 Vue 3、Vite、TypeScript 与 Monorepo 架构的完整权限体系支持前端角色路由控制、后端接口动态路由、前后端混合控制三种访问控制模式并提供组件、API、指令三种细粒度按钮权限实现方式。本文以官方英文文档 Access Control 为主体骨架结合仓库源码packages/effects/access与 playground 应用的真实实现系统讲解如何配置路由权限、接入后端菜单接口、控制按钮显隐帮助你根据业务复杂度选择并落地合适的权限方案。三种访问控制模式总览框架内置的访问控制方法分为以下三类由app.accessMode配置项驱动模式取值适用场景路由来源前端访问控制frontend角色相对固定、权限模型简单的系统前端路由表中按角色过滤后端访问控制backend权限复杂、需要后端动态下发菜单的系统后端接口返回的菜单数据混合访问控制mixed需要兼顾性能与灵活性的复杂业务前端固定路由 后端动态菜单并行合并accessMode的默认值为frontend其类型定义与默认值可以在 packages/core/preferences/src/config.ts 与 packages/core/preferences/src/types.ts 中确认。三种模式的实现分派逻辑统一收敛在 packages/effects/access/src/accessible.ts 的generateRoutes函数中async function generateRoutes(mode, options) { switch (mode) { case backend: resultRoutes await generateRoutesByBackend(options); break; case frontend: resultRoutes await generateRoutesByFrontend(routes, roles || [], forbiddenComponent); break; case mixed: { const [frontend_resultRoutes, backend_resultRoutes] await Promise.all([ generateRoutesByFrontend(routes, roles || [], forbiddenComponent), generateRoutesByBackend(options), ]); resultRoutes mergeRoutesByName(backend_resultRoutes, frontend_resultRoutes); break; } } }可以看到混合模式内部其实是并行执行前端过滤与后端菜单拉取再通过mergeRoutesByName按路由name合并两部分路由后端路由作为基准后端meta在冲突时优先这正是前端性能 后端灵活的实现本质。前端访问控制Frontend实现原理前端权限的实现原理路由权限硬编码在前端明确指定访问某些路由需要什么权限初始化时只注册通用路由需要权限的路由不加入路由表。登录拿到用户角色后用角色遍历路由表生成该角色可访问的路由表并通过router.addRoute加入路由实例从而完成权限过滤。劣势权限相对不灵活如果后端变更角色前端需要同步调整适合角色较为固定的系统。配置步骤第 1 步确认当前模式为前端访问控制调整对应应用目录下的preferences.ts确保accessModefrontendimport { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides app: { // Default value, optional accessMode: frontend, }, });第 2 步配置路由权限在路由的meta中声明authority数组标识该路由需要哪些角色才能访问{ meta: { authority: [super], }, },不配置authority时默认可见——即未声明权限的路由对所有登录用户开放。第 3 步保证接口返回的角色与路由表权限匹配在应用目录下的src/store/auth中可以找到类似下面的代码// 设置登录用户信息确保 userInfo.roles 是一个数组且包含路由表中的权限 // 例如userInfo.roles[super, admin] userStore.setUserInfo(userInfo);此时配置完成。需要确保登录后接口返回的角色与路由表权限一致否则无法访问对应路由。源码级过滤逻辑前端过滤的核心实现在 packages/utils/src/helpers/generate-routes-frontend.ts先用filterTree基于hasAuthority过滤路由树再在传入forbiddenComponent时将标记为menuVisibleWithForbidden的路由组件替换为 403 页面。function hasAuthority(route: RouteRecordRaw, access: string[]) { const authority route.meta?.authority; if (!authority) { return true; // 未配置 authority 默认可见 } const canAccess access.some((value) authority.includes(value)); return canAccess || (!canAccess menuHasVisibleWithForbidden(route)); }菜单可见但访问被禁止有时需要菜单可见但禁止访问。将menuVisibleWithForbidden设为true即可此时菜单正常显示但点击访问会被重定向到 403 页面。{ meta: { menuVisibleWithForbidden: true, }, },从源码可以看到该能力在前后端两种生成路由的实现中都得到了支持前端方式见 generate-routes-frontend.ts后端方式见 generate-routes-backend.ts。403 页面组件由应用侧的forbiddenComponent提供例如 playground 中注册为#/views/_core/fallback/forbidden.vue见 playground/src/router/access.ts。后端访问控制Backend实现原理后端访问控制的实现原理通过 API 动态生成路由表接口返回遵循一定结构的数据前端将其处理为可识别的结构后通过router.addRoute加入路由实例实现权限的动态生成。劣势后端需要提供符合标准的数据结构前端需要处理该结构适合权限较复杂的系统。配置步骤第 1 步确认当前模式为后端访问控制import { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides app: { accessMode: backend, }, });第 2 步确保接口返回的菜单数据结构正确应用目录下的src/router/access.ts中可以看到如下代码其中getAllMenus即后端菜单接口async function generateAccess(options: GenerateMenuAndRoutesOptions) { return await generateAccessible(preferences.app.accessMode, { fetchMenuListAsync: async () { // This interface is for the menu data returned by the backend return await getAllMenus(); }, }); }playground 中的完整实现playground/src/router/access.ts会额外传入pageMap通过import.meta.glob(../views/**/*.vue)收集的页面组件映射、layoutMapBasicLayout与IFrameView以及 403 组件供后端字符串形式的组件名转换为真实组件。第 3 步接口返回菜单数据注释即约定const dashboardMenus [ { // 这里的 BasicLayout 是硬编码的不能更改 component: BasicLayout, meta: { order: -1, title: page.dashboard.title, }, name: Dashboard, path: /dashboard, redirect: /dashboard/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, }, }, ], }, ];后端菜单数据的关键约定component字段为字符串顶层布局组件固定为BasicLayout或IFrameView见layoutMap页面组件写去掉views/前缀与.vue后缀的路径如/dashboard/analytics/indexmeta.order控制菜单排序meta.title支持 i18n key如page.dashboard.titlemeta.affixTab表示固定标签页子路由的path使用相对路径如analytics无需加前导/。此时配置完成。需要确保登录后接口返回的菜单格式正确否则无法访问对应路由。字符串组件名如何转换为真实组件后端返回的字符串组件名由 packages/utils/src/helpers/generate-routes-backend.ts 的convertRoutes处理先查layoutMap匹配布局否则通过normalizeViewPath归一化路径去掉./、../前缀、补全前导/、去掉/views前缀后在pageMap中查找真实组件若找不到则回退为/_core/fallback/not-found.vue并在控制台输出route component is invalid错误方便排查。混合访问控制Mixed实现原理与优势实现原理混合模式同时结合前端访问控制与后端访问控制两种方式系统并行处理前端固定路由权限与后端动态菜单数据最终合并两部分路由提供更灵活的权限方案。优势兼具前端控制的性能优势与后端控制的灵活性适合需要权限管理的复杂业务场景。配置步骤第 1 步确认当前模式为混合访问控制import { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides app: { accessMode: mixed, }, });第 2 步配置前端路由权限与前端访问控制模式中的路由权限配置方式相同。第 3 步配置后端菜单接口与后端访问控制模式中的接口配置方式相同。第 4 步保证角色与权限匹配必须同时满足前端路由权限配置与后端菜单数据返回要求确保用户角色与两种模式的权限配置都匹配。此时配置完成。混合模式会自动合并前端与后端路由提供完整的访问控制能力。合并策略按 name 去重合并两种来源的路由通过 accessible.ts 中的mergeRoutesByName合并以后端路由为基准构建Mapname, route前端路由中与后端同名含子路由的按name深度合并后端meta优先其余前端路由直接追加。这一策略保证了前后端菜单可以按路由name精确对齐而不是简单拼接。权限流程与路由守卫无论选择哪种模式权限的落地都发生在路由守卫中。playground 的 router/guard.ts 展示了完整流程基础路由coreRouteNames如登录页直接放行无accessToken时跳转登录页并携带redirect参数便于登录后回跳已登录且未生成过动态路由accessStore.isAccessChecked为false时调用generateAccess({ roles: userRoles, router, routes: accessRoutes })生成菜单与路由将结果写入accessStoresetAccessMenus/setAccessRoutes/setIsAccessChecked(true)后重新解析目标路径完成跳转。generateAccessibleaccessible.ts负责将生成的路由动态挂载到根路由children或直接router.addRoute再基于最终路由树生成菜单返回{ accessibleMenus, accessibleRoutes }。另外框架对路由树还做了自动化的redirect 归一化accessible.ts为未声明redirect的父路由自动生成指向首个子路由的绝对路径重定向对:id形式的动态首子路由则跳过自动重定向避免地址栏出现字面量:id导致 404。这些规则都有对应的单元测试覆盖见 packages/effects/access/src/tests/accessible.test.ts。按钮的细粒度权限控制在部分场景下需要更细粒度地控制按钮的显示。框架支持通过权限码或角色两种方式控制每种方式都提供组件、API、指令三种用法。相关实现位于 packages/effects/access/srcaccess-control.vueAccessControl组件内部基于useAccess计算hasAuth未通过时不渲染插槽内容codes为空时默认渲染slot v-if!codesuse-access.tsuseAccess组合式函数核心是hasAccessByRoles与hasAccessByCodes两者均通过Set求交集判断至少命中一个即放行并额外暴露accessMode与toggleAccessModedirective.tsv-access全局指令通过registerAccessDirective(app)注册无权限时直接el?.remove()移除元素。权限码Permission Code权限码是接口返回的字符串数组例如[AC_100100, AC_100110, AC_100120, AC_100010]。获取权限码的逻辑位于应用下的src/store/authconst [fetchUserInfoResult, accessCodes] await Promise.all([ fetchUserInfo(), getAccessCodes(), ]); userInfo fetchUserInfoResult; userStore.setUserInfo(userInfo); accessStore.setAccessCodes(accessCodes);定位到getAccessCodes对应的接口可根据业务逻辑自行调整。组件方式需要显式指定typecodescript langts setup import { AccessControl, useAccess } from vben/access; const { accessMode, hasAccessByCodes } useAccess(); /script template !-- 需要指定 typecode -- AccessControl :codes[AC_100100] typecode Button Visible to Super account [AC_1000001] /Button /AccessControl AccessControl :codes[AC_100030] typecode Button Visible to Admin account [AC_100010] /Button /AccessControl AccessControl :codes[AC_1000001] typecode Button Visible to User account [AC_1000001] /Button /AccessControl AccessControl :codes[AC_100100, AC_100010] typecode Button Visible to Super Admin account [AC_100100,AC_1000001] /Button /AccessControl /templateAPI 方式script langts setup import { AccessControl, useAccess } from vben/access; const { hasAccessByCodes } useAccess(); /script template Button v-ifhasAccessByCodes([AC_100100]) Visible to Super account [AC_1000001] /Button Button v-ifhasAccessByCodes([AC_100030]) Visible to Admin account [AC_100010] /Button Button v-ifhasAccessByCodes([AC_1000001]) Visible to User account [AC_1000001] /Button Button v-ifhasAccessByCodes([AC_100100, AC_1000001]) Visible to Super Admin account [AC_100100,AC_1000001] /Button /template指令方式指令支持绑定单个或多个权限码单个权限码可传字符串或只含一个权限码的数组多个权限码直接传数组。template Button classmr-4 v-access:codeAC_100100 Visible to Super account AC_100100 /Button Button classmr-4 v-access:code[AC_100030] Visible to Admin account [AC_100010] /Button Button classmr-4 v-access:code[AC_1000001] Visible to User account [AC_1000001] /Button Button classmr-4 v-access:code[AC_100100, AC_1000001] Visible to Super Admin account [AC_100100,AC_1000001] /Button /template注意指令内部的一个细节directive.tsv-access:role在前端模式下走角色判断其余情况v-access:code或非前端模式一律走权限码判断。角色Roles角色方式不依赖接口返回的权限码直接根据用户角色判断按钮是否显示。组件方式script langts setup import { AccessControl } from vben/access; /script template AccessControl :codes[super] Button Visible to Super account /Button /AccessControl AccessControl :codes[admin] Button Visible to Admin account /Button /AccessControl AccessControl :codes[user] Button Visible to User account /Button /AccessControl AccessControl :codes[super, admin] Button Super Visible to Admin account /Button /AccessControl /template组件默认typerole因此角色方式无需指定type。API 方式script langts setup import { useAccess } from vben/access; const { hasAccessByRoles } useAccess(); /script template Button v-ifhasAccessByRoles([super]) Visible to Super account /Button Button v-ifhasAccessByRoles([admin]) Visible to Admin account /Button Button v-ifhasAccessByRoles([user]) Visible to User account /Button Button v-ifhasAccessByRoles([super, admin]) Super Visible to Admin account /Button /template指令方式template Button classmr-4 v-access:rolesuper Visible to Super account /Button Button classmr-4 v-access:role[admin] Visible to Admin account /Button Button classmr-4 v-access:role[user] Visible to User account /Button Button classmr-4 v-access:role[super, admin] Super Visible to Admin account /Button /template三种用法的取舍组件方式AccessControl声明式、可读性好适合模板结构固定的场景未命中时只是不渲染插槽不会破坏 DOM 结构API 方式hasAccessByRoles/hasAccessByCodes最灵活可在任意逻辑如v-if、计算属性、事件回调中复用权限判断指令方式v-access最简洁但无权限时直接移除 DOM 元素适用于纯显隐控制。实战要点小结选型角色固定、权限简单选frontend权限复杂、菜单需后端动态下发选backend两者兼顾选mixed。模式统一通过应用目录下preferences.ts的app.accessMode切换。角色一致性前端模式下登录接口返回的userInfo.roles必须是数组且与路由meta.authority中的角色字符串完全一致。菜单数据约定后端模式下顶层component固定为BasicLayout页面组件路径去掉views/与.vuename必须唯一convertRoutes会校验并输出route name is required错误。403 处理menuVisibleWithForbidden: true让菜单可见但访问跳转 403适用于功能存在但需申请权限的场景403 组件通过forbiddenComponent注入。按钮权限优先使用权限码accessCodes做细粒度控制角色判断适合粗粒度场景组件、API、指令三种用法可按团队习惯混用。排查手段后端组件转换失败会在控制台打印route component is invalid: xxx路由生成与合并逻辑均有单元测试accessible.test.ts、generate-routes-frontend.test.ts可据此验证预期行为。【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门