导航守卫与权限路由
约 975 字大约 3 分钟
布欧-Lewyon
2026-05-15
首页 › Vue › 路由与状态管理 › 导航守卫与权限路由
导航守卫(Navigation Guard)是 Vue Router 提供的"路由拦截"机制,用于在导航发生前后执行逻辑——身份验证、权限检查、页面标题设置、数据预加载等。
三种守卫
全局前置守卫
// router/index.ts
import { createRouter } from 'vue-router'
const router = createRouter({ ... })
router.beforeEach(async (to, from) => {
// to: 目标路由对象
// from: 来源路由对象
// 1. 设置页面标题
document.title = `${to.meta.title} | 我的站点`
// 2. 登录检查
const isLoggedIn = useAuthStore().isLoggedIn
if (to.meta.requiresAuth && !isLoggedIn) {
return { name: 'login', query: { redirect: to.fullPath } }
}
// 3. 角色检查
if (to.meta.roles && !to.meta.roles.includes(userStore.role)) {
return { name: '403' }
}
// 4. 数据预加载
if (to.meta.fetchData) {
await store.dispatch(to.meta.fetchData)
}
// return undefined → 正常导航
// return false → 取消导航
// return 路径 → 重定向
})全局解析守卫
router.beforeResolve(async (to) => {
// 所有守卫和组件内的守卫都解析完成后执行
// 适合做数据预取,确保数据在渲染前到位
})全局后置钩子
router.afterEach((to, from, failure) => {
// 导航完成后(此时视图已经更新)
// 适合:页面埋点、进度条完成、滚动恢复
if (to.hash) {
setTimeout(() => {
document.querySelector(to.hash)?.scrollIntoView()
}, 100)
}
})路由独享守卫
const routes = [
{
path: '/admin',
component: AdminPanel,
beforeEnter: (to, from) => {
// 只在这个路由进入时触发(params/query 变化不触发)
if (!useAuthStore().isAdmin) {
return { name: '403' }
}
}
}
]组件内守卫
<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
// 离开当前路由前
onBeforeRouteLeave((to, from) => {
const answer = window.confirm('确定离开吗?未保存的内容将丢失')
if (!answer) return false // 取消导航
})
// 路由参数变化时(同一组件参数变化)
onBeforeRouteUpdate((to, from) => {
// 更新组件数据以匹配新的路由参数
fetchUser(to.params.id)
})
</script>完整的导航解析流程
导航被触发
→ 失活组件的 onBeforeRouteLeave
→ 全局 router.beforeEach
→ 路由独享 beforeEnter
→ 新组件的 onBeforeRouteUpdate(如有)
→ 全局 router.beforeResolve
→ 导航确认
→ 更新 DOM
→ 全局 router.afterEach
→ 触发 DOM 更新
→ 调用 onMounted / onActivated(新组件)权限路由实战
Route Meta
// router/index.ts
const routes = [
{
path: '/dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: {
title: '仪表盘',
requiresAuth: true,
roles: ['admin', 'editor'],
permission: 'dashboard:view'
}
},
{
path: '/admin/users',
component: () => import('@/views/admin/Users.vue'),
meta: {
title: '用户管理',
requiresAuth: true,
roles: ['admin'],
permission: 'user:manage'
}
},
{
path: '/login',
component: () => import('@/views/Login.vue'),
meta: { title: '登录', guest: true } // 仅未登录可访问
}
]路由守卫 + 权限校验
// router/permission.ts
import router from './index'
import { useUserStore } from '@/stores/user'
const WHITE_LIST = ['/login', '/register', '/403', '/404']
router.beforeEach(async (to, from) => {
const userStore = useUserStore()
document.title = `${to.meta.title} | 管理系统`
// 白名单直接放行
if (WHITE_LIST.includes(to.path)) return true
// 未登录 → 跳转登录
if (!userStore.isLoggedIn) {
// 尝试自动登录(token 验证)
try {
await userStore.fetchUser()
} catch {
return { path: '/login', query: { redirect: to.fullPath } }
}
}
// 角色检查
if (to.meta.roles && !to.meta.roles.includes(userStore.role)) {
return { name: '403' }
}
// 权限检查
if (to.meta.permission && !userStore.hasPermission(to.meta.permission)) {
return { name: '403' }
}
})动态路由
后台管理系统常见的模式——根据用户角色动态添加路由:
// router/dynamic.ts
import router from './index'
// 定义所有路由映射
const asyncRouteMap = {
admin: [
{
path: '/admin/dashboard',
component: () => import('@/views/admin/Dashboard.vue'),
meta: { title: '管理仪表盘', permission: 'admin:dashboard' }
},
{
path: '/admin/users',
component: () => import('@/views/admin/Users.vue'),
meta: { title: '用户管理', permission: 'admin:users' }
}
],
editor: [
{
path: '/editor/posts',
component: () => import('@/views/editor/Posts.vue'),
meta: { title: '文章管理', permission: 'editor:posts' }
}
]
}
// 登录成功后根据角色动态添加
function setupDynamicRoutes(role) {
const routes = asyncRouteMap[role] || []
routes.forEach(route => {
// 避免重复添加
if (!router.hasRoute(route.name)) {
router.addRoute('main', route) // 添加到 main 布局下
}
})
}小结
| 守卫类型 | API | 执行时机 |
|---|---|---|
| 全局前置 | router.beforeEach | 路由切换前 |
| 全局解析 | router.beforeResolve | 所有组件守卫后 |
| 全局后置 | router.afterEach | 导航完成 |
| 路由独享 | beforeEnter | 进入路由前 |
| 组件内 | onBeforeRouteLeave | 离开当前页 |
| 组件内 | onBeforeRouteUpdate | 路由参数变化 |
上一节:Vue Router 基础 下一节:Pinia 状态管理
