Vue 3 + Element Plus 权限后台最小架构:菜单、路由、按钮和接口怎么统一

HTMLPAGE 团队
15 分钟阅读

权限后台不是只隐藏菜单。本文用 Vue 3 和 Element Plus 讲清菜单权限、路由守卫、按钮权限、接口兜底和页面状态的最小可维护架构。

#Vue 3 #Element Plus #权限后台 #前端架构

很多后台系统一开始只是“登录后看到菜单”,后来才发现权限问题远不止菜单:路由能不能直接访问、按钮要不要显示、接口失败怎么提示、数据范围如何表达、页面刷新后状态如何恢复。

本文给出一套 Vue 3 + Element Plus 后台的最小权限架构,适合中小团队从混乱状态走向可维护。

先给结论:权限至少要覆盖四层

层级负责什么前端职责
菜单权限用户能看到哪些入口渲染导航和侧边栏
路由权限用户能进入哪些页面守卫、重定向、403 页
按钮权限用户能做哪些动作控制操作入口
接口权限最终是否允许执行处理后端拒绝结果

前端权限提升体验,后端权限保证最终边界。两者不能互相替代。

一、权限数据不要散落在页面里

权限最好用统一结构表达:

interface PermissionState {
  menus: string[]
  actions: string[]
  roles: string[]
}

const can = (code: string) => permission.actions.includes(code)

页面里不要到处写 role === 'admin'。角色是人的分组,权限是动作边界。长期看,基于权限码判断比基于角色判断更灵活。

二、菜单和路由可以同源,但不要完全等同

菜单用于展示入口,路由用于页面访问。某些页面可能不出现在菜单里,例如详情页、编辑页、结果页,但仍然需要权限判断。

建议路由 meta 中声明权限:

{
  path: '/users',
  component: UserList,
  meta: { permission: 'user:view' }
}

路由守卫检查 meta,菜单根据同一套权限码过滤。这样可以保持一致,又不把菜单结构当成全部路由结构。

三、按钮权限要和业务状态一起判断

按钮能不能点,不只由权限决定,还由当前数据状态决定。

例如删除按钮:

const canDeleteUser = (row: User) => {
  return can('user:delete') && row.status !== 'locked'
}

模板里只负责展示:

<el-button v-if="canDeleteUser(row)" link type="danger">删除</el-button>

把判断函数集中起来,后续规则变化时更容易维护。

四、接口拒绝要有统一处理

即使前端隐藏了按钮,用户仍可能通过旧页面、直接请求或权限变化触发接口拒绝。接口层要统一处理 401、403 和业务拒绝。

推荐策略:

  • 401:登录失效,引导重新登录
  • 403:权限不足,显示明确提示或进入 403 页
  • 业务状态冲突:在页面内展示可理解原因

不要让每个页面自己随意处理权限失败,否则体验会不一致。

五、页面刷新后权限要可恢复

权限状态不能只存在内存中。刷新页面后,应用需要根据 token 或会话重新拉取用户信息和权限,再初始化路由和菜单。

初始化顺序建议:

读取登录态 -> 获取用户信息 -> 获取权限 -> 注册/过滤路由 -> 渲染布局

如果权限未加载就渲染页面,容易出现菜单闪烁、路由误拦截或按钮短暂显示。

六、失败案例:只隐藏菜单,直接访问 URL 仍可进入

一个内部系统根据权限隐藏了侧边栏菜单,但没有做路由守卫。用户复制旧链接后仍能进入页面,只是在调用接口时失败。体验上看像页面坏了,安全边界也不清晰。

修复方式:

  1. 路由 meta 声明页面权限
  2. 守卫在进入前判断权限
  3. 无权限进入 403 页
  4. 接口层继续处理 403 作为最终兜底
  5. 按钮权限只作为体验优化,不作为唯一边界

七、权限后台 Checklist

  • 权限码是否统一管理,而不是散落在页面
  • 菜单权限和路由权限是否使用同一套来源
  • 非菜单页是否也声明权限
  • 按钮权限是否结合业务状态判断
  • 接口 401/403 是否统一处理
  • 刷新页面后权限是否能恢复
  • 是否有清晰的 403、空态和加载状态

结语

权限后台的核心不是“藏按钮”,而是让入口、页面、动作和接口形成一致边界。Vue 3 和 Element Plus 能快速搭出界面,但权限模型需要从一开始就清楚,否则页面越多,补丁越多。

延伸阅读: