Vue Router 权限系统设计实战

@toc

在 Vue 项目里,权限问题永远不是"有没有",而是"会不会失控"

一开始可能只是:

  • 登录校验
  • 菜单控制
  • 页面访问限制

但随着业务复杂度上来,很容易演变成:

  • 路由守卫越写越多
  • 页面里到处是 if (hasPermission)
  • 前后端权限逻辑不一致

这篇文章,我们不讲"能跑的权限",而是讲可扩展、可维护、长期稳定的权限系统设计

一、先明确:权限系统到底在管什么?

先给一个非常重要的拆分:

权限 = 三件事

  1. 能不能进这个路由
  2. 能不能看到这个页面的入口
  3. 能不能执行某个操作(按钮级)

这篇文章重点讲 第 1 件事:路由权限

二、权限设计的核心原则

在任何中大型项目里,下面三条原则一定要守住。

原则一:权限是"声明式"的

路由只声明自己需要什么权限,而不是怎么判断。

ts 复制代码
meta: {
  requiresAuth: true,
  roles: ['admin']
}

原则二:权限判断逻辑集中

绝不分散在页面、组件、API 调用里。

原则三:路由权限 ≠ 菜单权限

  • 路由权限:是否允许访问 URL
  • 菜单权限:是否展示入口

两者相关,但不要强耦合。

三、基础路由权限模型

路由声明

ts 复制代码
{
  path: '/admin',
  component: () => import('@/views/admin/index.vue'),
  meta: {
    requiresAuth: true,
    roles: ['admin']
  }
}

全局守卫

ts 复制代码
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isLogin()) {
    return next('/login')
  }
  next()
})

这是最基础的一层,但还远远不够。

四、角色权限系统的正确写法

权限判断函数集中化

ts 复制代码
function hasPermission(routeRoles: string[]) {
  const userRoles = getUserRoles()
  return routeRoles.some(role => userRoles.includes(role))
}

权限守卫

ts 复制代码
router.beforeEach((to, from, next) => {
  const { roles } = to.meta
  if (roles && !hasPermission(roles)) {
    return next('/403')
  }
  next()
})

好处:

  • 权限逻辑只有一个入口
  • 改规则不用全局搜代码

五、动态路由与后端权限

中后台项目几乎都会遇到:

路由由后端返回,前端动态注册

后端返回示例

json 复制代码
[
  {
    "path": "/order",
    "component": "order/index",
    "roles": ["admin"]
  }
]

前端动态注册

ts 复制代码
const asyncRoutes = mapBackendRoutes(routesFromServer)
asyncRoutes.forEach(route => {
  router.addRoute(route)
})

关键点

  • 前端仍然保留权限校验
  • 后端负责"能看到什么"
  • 前端负责"能不能访问"

六、权限与页面逻辑解耦

错误示例:

vue 复制代码
<button v-if="user.role === 'admin'">删除</button>

正确做法:

ts 复制代码
const canDelete = usePermission('delete_order')

统一用权限 Hook / 方法,避免散落逻辑。

七、实战总结

一个稳定的 Vue Router 权限系统应该做到:

  • 路由声明权限
  • 守卫集中判断
  • 页面不感知权限逻辑
  • 支持后端动态配置
相关推荐
用户62960593247059 小时前
从“浏览器根本区分不了”到真正实现:刷新不退出,关闭标签页自动退出,前端判断浏览器关闭和刷新
前端
qetfw9 小时前
MWU:Vue 3 + FastAPI 的 MaaFramework 跨平台 WebUI 源码
前端·vue.js·python·fastapi·开源项目·效率工具
mfxcyh9 小时前
Vue3+Ant Design Vue 实现手动异步文件上传(含大小校验、弹窗上传)
前端·javascript·vue.js
wordbaby9 小时前
Web端热敏标签打印完整解决方案(QZ Tray + 译维A42)
前端
swipe10 小时前
03|Axios 请求进了后端之后:Controller、Request、Response 是怎么接住它的?
前端·后端·全栈
meilindehuzi_a10 小时前
Vue3进阶基础:指令修饰符、v-model表单绑定、动态样式、计算属性与侦听器实战
前端·javascript·vue.js
csdn2015_10 小时前
vue 前端运行命令
前端·javascript·vue.js
swipe10 小时前
02|从 `pnpm dev` 到 Spring Boot 启动:后端服务到底怎么跑起来?
前端·后端·全栈
swipe10 小时前
01|前端人第一次打开 Spring Boot 项目,应该先看哪里?
前端·后端·全栈
Cobyte10 小时前
根据浏览器解析 HTML 的规范实现 HTML 解析器
前端·javascript·vue.js