👋 大家好,我是 阿问学长
!专注于分享优质开源项目
解析、毕业设计项目指导
支持、幼小初高
的教辅资料
推荐等,欢迎关注交流!🚀
Vue Router路由守卫与权限控制深度解析
🎯 学习目标
通过本文,你将深入掌握:
- 路由守卫的设计理念和执行机制
- 全局守卫、路由守卫、组件守卫的应用场景
- 企业级权限控制系统的设计和实现
- 动态权限验证和角色管理的最佳实践
- 路由守卫的性能优化和错误处理策略
🛡️ 路由守卫的设计理念
守卫系统的架构思想
Vue Router的守卫系统基于"洋葱模型"设计,提供了多层次的拦截和控制机制。这种设计允许开发者在路由跳转的不同阶段插入自定义逻辑,实现精细化的访问控制。
传统权限控制的问题:
javascript
// ❌ 传统方式:在组件内部进行权限检查
export default {
async created() {
// 每个组件都需要重复的权限检查逻辑
if (!this.$store.state.user.isAuthenticated) {
this.$router.push('/login')
return
}
if (!this.hasPermission('view-dashboard')) {
this.$router.push('/forbidden')
return
}
// 业务逻辑
await this.loadDashboardData()
},
methods: {
hasPermission(permission) {
// 权限检查逻辑分散在各个组件中
return this.$store.state.user.permissions.includes(permission)
}
}
}
路由守卫的优雅解决方案:
javascript
// ✅ 路由守卫:集中化的权限控制
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/dashboard',
component: Dashboard,
meta: {
requiresAuth: true,
permissions: ['view-dashboard'],
roles: ['admin', 'user']
}
}
]
})
// 全局前置守卫:统一的权限检查
router.beforeEach(async (to, from, next) => {
const authStore = useAuthStore()
// 认证检查
if (to.meta.requiresAuth && !authStore.isAuthenticated) {
return next('/login')
}
// 权限检查
if (to.meta.permissions && !authStore.hasPermissions(to.meta.permissions)) {
return next('/forbidden')
}
next()
})
守卫执行的完整流程
理解守卫的执行顺序对于构建复杂的权限系统至关重要:
javascript
// 守卫执行流程示例
const guardExecutionFlow = {
// 1. 全局前置守卫(按注册顺序执行)
globalBeforeGuards: [
// 认证守卫
async (to, from, next) => {
console.log('1. 执行认证检查')
const isAuthenticated = await checkAuthentication()
if (!isAuthenticated && to.meta.requiresAuth) {
return next('/login')
}
next()
},
// 权限守卫
async (to, from, next) => {
console.log('2. 执行权限检查')
const hasPermission = await checkPermissions(to.meta.permissions)
if (!hasPermission) {
return next('/forbidden')
}
next()
},
// 数据预加载守卫
async (to, from, next) => {
console.log('3. 执行数据预加载')
if (to.meta.preload) {
await preloadRouteData(to)
}
next()
}
],
// 2. 路由独享守卫
routeBeforeEnter: async (to, from, next) => {
console.log('4. 执行路由独享守卫')
// 特定路由的检查逻辑
next()
},
// 3. 组件内守卫
componentGuards: {
beforeRouteEnter: (to, from, next) => {
console.log('5. 组件beforeRouteEnter')
next()
},
beforeRouteUpdate: (to, from, next) => {
console.log('6. 组件beforeRouteUpdate')
next()
},
beforeRouteLeave: (to, from, next) => {
console.log('7. 组件beforeRouteLeave')
next()
}
},
// 4. 全局解析守卫
globalResolveGuards: [
(to, from, next) => {
console.log('8. 全局解析守卫')
next()
}
],
// 5. 全局后置钩子
globalAfterHooks: [
(to, from) => {
console.log('9. 全局后置钩子')
// 页面统计、标题更新等
}
]
}
🔐 企业级权限控制系统
RBAC权限模型的实现
基于角色的访问控制(RBAC)是企业应用中最常用的权限模型:
javascript
// 权限管理核心类
class PermissionManager {
constructor() {
this.permissions = new Map()
this.roles = new Map()
this.userRoles = new Map()
this.rolePermissions = new Map()
}
// 定义权限
definePermission(permission) {
const { id, name, description, resource, action } = permission
this.permissions.set(id, {
id,
name,
description,
resource, // 资源类型:user, project, report等
action, // 操作类型:create, read, update, delete等
createdAt: Date.now()
})
}
// 定义角色
defineRole(role) {
const { id, name, description, level } = role
this.roles.set(id, {
id,
name,
description,
level, // 角色级别,用于层级权限控制
createdAt: Date.now()
})
}
// 为角色分配权限
assignPermissionToRole(roleId, permissionId) {
if (!this.rolePermissions.has(roleId)) {
this.rolePermissions.set(roleId, new Set())
}
this.rolePermissions.get(roleId).add(permissionId)
}
// 为用户分配角色
assignRoleToUser(userId, roleId) {
if (!this.userRoles.has(userId)) {
this.userRoles.set(userId, new Set())
}
this.userRoles.get(userId).add(roleId)
}
// 检查用户是否有特定权限
hasPermission(userId, permissionId) {
const userRoles = this.userRoles.get(userId) || new Set()
for (const roleId of userRoles) {
const rolePermissions = this.rolePermissions.get(roleId) || new Set()
if (rolePermissions.has(permissionId)) {
return true
}
}
return false
}
// 检查用户是否有特定角色
hasRole(userId, roleId) {
const userRoles = this.userRoles.get(userId) || new Set()
return userRoles.has(roleId)
}
// 获取用户的所有权限
getUserPermissions(userId) {
const userRoles = this.userRoles.get(userId) || new Set()
const permissions = new Set()
for (const roleId of userRoles) {
const rolePermissions = this.rolePermissions.get(roleId) || new Set()
for (const permissionId of rolePermissions) {
permissions.add(permissionId)
}
}
return Array.from(permissions).map(id => this.permissions.get(id))
}
// 检查资源级权限
hasResourcePermission(userId, resource, action, resourceId = null) {
const userPermissions = this.getUserPermissions(userId)
return userPermissions.some(permission => {
// 基础权限检查
if (permission.resource === resource && permission.action === action) {
// 如果没有指定资源ID,表示有全局权限
if (!resourceId) return true
// 检查特定资源的权限
return this.checkResourceAccess(userId, resource, resourceId)
}
return false
})
}
// 检查特定资源的访问权限
checkResourceAccess(userId, resource, resourceId) {
// 这里可以实现更复杂的资源级权限逻辑
// 例如:用户只能访问自己创建的资源,或者所属部门的资源
return true // 简化实现
}
}
// 初始化权限系统
const permissionManager = new PermissionManager()
// 定义权限
const permissions = [
{ id: 'user.create', name: '创建用户', resource: 'user', action: 'create' },
{ id: 'user.read', name: '查看用户', resource: 'user', action: 'read' },
{ id: 'user.update', name: '更新用户', resource: 'user', action: 'update' },
{ id: 'user.delete', name: '删除用户', resource: 'user', action: 'delete' },
{ id: 'project.create', name: '创建项目', resource: 'project', action: 'create' },
{ id: 'project.read', name: '查看项目', resource: 'project', action: 'read' },
{ id: 'report.read', name: '查看报表', resource: 'report', action: 'read' }
]
permissions.forEach(permission => {
permissionManager.definePermission(permission)
})
// 定义角色
const roles = [
{ id: 'admin', name: '管理员', level: 100 },
{ id: 'manager', name: '经理', level: 50 },
{ id: 'user', name: '普通用户', level: 10 }
]
roles.forEach(role => {
permissionManager.defineRole(role)
})
// 分配权限给角色
// 管理员拥有所有权限
permissions.forEach(permission => {
permissionManager.assignPermissionToRole('admin', permission.id)
})
// 经理拥有部分权限
['user.read', 'user.update', 'project.create', 'project.read', 'report.read'].forEach(permissionId => {
permissionManager.assignPermissionToRole('manager', permissionId)
})
// 普通用户只有基础权限
['project.read', 'report.read'].forEach(permissionId => {
permissionManager.assignPermissionToRole('user', permissionId)
})
动态权限验证系统
javascript
// 动态权限验证器
class DynamicPermissionValidator {
constructor(permissionManager) {
this.permissionManager = permissionManager
this.validationRules = new Map()
this.contextProviders = new Map()
}
// 注册验证规则
registerRule(name, rule) {
this.validationRules.set(name, rule)
}
// 注册上下文提供者
registerContextProvider(name, provider) {
this.contextProviders.set(name, provider)
}
// 验证权限
async validate(userId, permission, context = {}) {
// 基础权限检查
if (!this.permissionManager.hasPermission(userId, permission)) {
return { allowed: false, reason: 'insufficient_permission' }
}
// 动态规则验证
const rule = this.validationRules.get(permission)
if (rule) {
try {
// 获取验证上下文
const validationContext = await this.buildContext(userId, context)
// 执行验证规则
const result = await rule(userId, validationContext)
if (!result.allowed) {
return result
}
} catch (error) {
console.error(`权限验证规则执行失败: ${permission}`, error)
return { allowed: false, reason: 'validation_error', error }
}
}
return { allowed: true }
}
// 构建验证上下文
async buildContext(userId, baseContext) {
const context = { ...baseContext, userId }
// 执行上下文提供者
for (const [name, provider] of this.contextProviders) {
try {
context[name] = await provider(userId, context)
} catch (error) {
console.error(`上下文提供者执行失败: ${name}`, error)
}
}
return context
}
// 批量验证权限
async validateBatch(userId, permissions, context = {}) {
const results = {}
for (const permission of permissions) {
results[permission] = await this.validate(userId, permission, context)
}
return results
}
}
// 初始化动态验证器
const validator = new DynamicPermissionValidator(permissionManager)
// 注册上下文提供者
validator.registerContextProvider('userInfo', async (userId) => {
return await userApi.getUser(userId)
})
validator.registerContextProvider('userDepartment', async (userId) => {
const user = await userApi.getUser(userId)
return await departmentApi.getDepartment(user.departmentId)
})
// 注册验证规则
validator.registerRule('user.update', async (userId, context) => {
const { targetUserId, userInfo, userDepartment } = context
// 用户只能更新自己的信息
if (targetUserId === userId) {
return { allowed: true }
}
// 经理可以更新同部门用户的信息
if (userInfo.role === 'manager') {
const targetUser = await userApi.getUser(targetUserId)
if (targetUser.departmentId === userDepartment.id) {
return { allowed: true }
}
}
return {
allowed: false,
reason: 'insufficient_authority',
message: '您只能更新自己或同部门用户的信息'
}
})
validator.registerRule('project.delete', async (userId, context) => {
const { projectId, userInfo } = context
// 只有项目创建者或管理员可以删除项目
const project = await projectApi.getProject(projectId)
if (project.createdBy === userId || userInfo.role === 'admin') {
return { allowed: true }
}
return {
allowed: false,
reason: 'not_project_owner',
message: '只有项目创建者或管理员可以删除项目'
}
})
路由级权限守卫的实现
javascript
// 高级路由权限守卫
class AdvancedRouteGuard {
constructor(router, permissionManager, validator) {
this.router = router
this.permissionManager = permissionManager
this.validator = validator
this.setupGuards()
}
setupGuards() {
// 认证守卫
this.router.beforeEach(async (to, from, next) => {
if (to.meta.requiresAuth) {
const authStore = useAuthStore()
if (!authStore.isAuthenticated) {
return next({
name: 'Login',
query: { redirect: to.fullPath }
})
}
// 检查用户状态
if (authStore.user.status === 'suspended') {
return next({ name: 'AccountSuspended' })
}
if (authStore.user.status === 'pending') {
return next({ name: 'AccountPending' })
}
}
next()
})
// 权限守卫
this.router.beforeEach(async (to, from, next) => {
const authStore = useAuthStore()
if (!authStore.isAuthenticated) {
return next()
}
// 角色检查
if (to.meta.roles && to.meta.roles.length > 0) {
const hasRole = to.meta.roles.some(role =>
this.permissionManager.hasRole(authStore.user.id, role)
)
if (!hasRole) {
return next({
name: 'Forbidden',
params: { reason: 'insufficient_role' }
})
}
}
// 权限检查
if (to.meta.permissions && to.meta.permissions.length > 0) {
const permissionResults = await this.validator.validateBatch(
authStore.user.id,
to.meta.permissions,
{ route: to, fromRoute: from }
)
const deniedPermissions = Object.entries(permissionResults)
.filter(([_, result]) => !result.allowed)
.map(([permission, result]) => ({ permission, result }))
if (deniedPermissions.length > 0) {
return next({
name: 'Forbidden',
params: {
reason: 'insufficient_permission',
details: deniedPermissions
}
})
}
}
// 动态权限检查
if (to.meta.dynamicPermission) {
const result = await this.validator.validate(
authStore.user.id,
to.meta.dynamicPermission,
{
route: to,
fromRoute: from,
...to.params
}
)
if (!result.allowed) {
return next({
name: 'Forbidden',
params: {
reason: result.reason,
message: result.message
}
})
}
}
next()
})
// 数据预加载守卫
this.router.beforeEach(async (to, from, next) => {
if (to.meta.preloadData) {
const loadingStore = useLoadingStore()
try {
loadingStore.setLoading(true, '正在加载页面数据...')
await this.preloadRouteData(to)
next()
} catch (error) {
console.error('路由数据预加载失败:', error)
// 根据错误类型决定处理方式
if (error.status === 403) {
return next({ name: 'Forbidden' })
} else if (error.status === 404) {
return next({ name: 'NotFound' })
} else {
return next({ name: 'Error', params: { error } })
}
} finally {
loadingStore.setLoading(false)
}
} else {
next()
}
})
// 页面离开确认守卫
this.router.beforeEach(async (to, from, next) => {
if (from.meta.confirmLeave) {
const confirmed = await this.confirmLeave(from, to)
if (!confirmed) {
return next(false)
}
}
next()
})
}
async preloadRouteData(route) {
const preloadConfig = route.meta.preloadData
if (typeof preloadConfig === 'function') {
return await preloadConfig(route)
}
if (Array.isArray(preloadConfig)) {
const promises = preloadConfig.map(loader => loader(route))
return await Promise.all(promises)
}
throw new Error('Invalid preload configuration')
}
async confirmLeave(fromRoute, toRoute) {
// 检查是否有未保存的更改
const hasUnsavedChanges = this.checkUnsavedChanges(fromRoute)
if (hasUnsavedChanges) {
return await this.showLeaveConfirmation(fromRoute, toRoute)
}
return true
}
checkUnsavedChanges(route) {
// 检查表单状态、编辑器状态等
const formStore = useFormStore()
return formStore.hasUnsavedChanges(route.name)
}
async showLeaveConfirmation(fromRoute, toRoute) {
const modalStore = useModalStore()
return new Promise((resolve) => {
modalStore.showConfirm({
title: '确认离开',
message: '您有未保存的更改,确定要离开当前页面吗?',
confirmText: '离开',
cancelText: '取消',
onConfirm: () => resolve(true),
onCancel: () => resolve(false)
})
})
}
}
// 初始化路由守卫
const routeGuard = new AdvancedRouteGuard(router, permissionManager, validator)
🎨 组件级权限控制
权限指令的实现
javascript
// 权限控制指令
const permissionDirective = {
mounted(el, binding, vnode) {
checkPermission(el, binding, vnode)
},
updated(el, binding, vnode) {
checkPermission(el, binding, vnode)
}
}
function checkPermission(el, binding, vnode) {
const { value, modifiers, arg } = binding
const authStore = useAuthStore()
if (!authStore.isAuthenticated) {
removeElement(el, modifiers)
return
}
let hasPermission = false
if (typeof value === 'string') {
// 单个权限检查
hasPermission = permissionManager.hasPermission(authStore.user.id, value)
} else if (Array.isArray(value)) {
// 多个权限检查
if (modifiers.all) {
// 需要所有权限
hasPermission = value.every(permission =>
permissionManager.hasPermission(authStore.user.id, permission)
)
} else {
// 需要任一权限
hasPermission = value.some(permission =>
permissionManager.hasPermission(authStore.user.id, permission)
)
}
} else if (typeof value === 'object') {
// 复杂权限检查
const { permissions, roles, validator: customValidator } = value
// 权限检查
if (permissions) {
const permissionCheck = Array.isArray(permissions)
? permissions.some(p => permissionManager.hasPermission(authStore.user.id, p))
: permissionManager.hasPermission(authStore.user.id, permissions)
if (!permissionCheck) {
hasPermission = false
}
}
// 角色检查
if (roles && hasPermission !== false) {
const roleCheck = Array.isArray(roles)
? roles.some(r => permissionManager.hasRole(authStore.user.id, r))
: permissionManager.hasRole(authStore.user.id, roles)
hasPermission = roleCheck
}
// 自定义验证器
if (customValidator && hasPermission !== false) {
hasPermission = customValidator(authStore.user, vnode.ctx)
}
}
if (!hasPermission) {
removeElement(el, modifiers)
} else {
restoreElement(el)
}
}
function removeElement(el, modifiers) {
if (modifiers.hide) {
// 隐藏元素
el.style.display = 'none'
} else if (modifiers.disable) {
// 禁用元素
el.disabled = true
el.classList.add('permission-disabled')
} else {
// 移除元素
if (el.parentNode) {
el.parentNode.removeChild(el)
}
}
}
function restoreElement(el) {
if (el.style.display === 'none') {
el.style.display = ''
}
if (el.disabled) {
el.disabled = false
el.classList.remove('permission-disabled')
}
}
// 注册指令
app.directive('permission', permissionDirective)
权限组件的封装
vue
<!-- PermissionWrapper.vue -->
<template>
<div v-if="hasPermission" class="permission-wrapper">
<slot v-if="!loading"></slot>
<div v-else class="permission-loading">
<LoadingSpinner />
<span>正在验证权限...</span>
</div>
</div>
<div v-else-if="showFallback" class="permission-fallback">
<slot name="fallback">
<div class="no-permission">
<Icon name="lock" />
<p>{{ fallbackMessage }}</p>
</div>
</slot>
</div>
</template>
<script>
import { ref, computed, watch, onMounted } from 'vue'
import { useAuthStore } from '@/stores/auth'
export default {
name: 'PermissionWrapper',
props: {
// 权限配置
permissions: {
type: [String, Array, Object],
default: null
},
// 角色配置
roles: {
type: [String, Array],
default: null
},
// 是否需要所有权限
requireAll: {
type: Boolean,
default: false
},
// 是否显示降级内容
showFallback: {
type: Boolean,
default: true
},
// 降级消息
fallbackMessage: {
type: String,
default: '您没有权限访问此内容'
},
// 异步验证器
asyncValidator: {
type: Function,
default: null
},
// 验证上下文
context: {
type: Object,
default: () => ({})
}
},
setup(props) {
const authStore = useAuthStore()
const loading = ref(false)
const hasPermission = ref(false)
// 权限检查
const checkPermissions = async () => {
if (!authStore.isAuthenticated) {
hasPermission.value = false
return
}
loading.value = true
try {
let permissionResult = true
// 基础权限检查
if (props.permissions) {
if (typeof props.permissions === 'string') {
permissionResult = permissionManager.hasPermission(
authStore.user.id,
props.permissions
)
} else if (Array.isArray(props.permissions)) {
if (props.requireAll) {
permissionResult = props.permissions.every(permission =>
permissionManager.hasPermission(authStore.user.id, permission)
)
} else {
permissionResult = props.permissions.some(permission =>
permissionManager.hasPermission(authStore.user.id, permission)
)
}
}
}
// 角色检查
if (permissionResult && props.roles) {
if (typeof props.roles === 'string') {
permissionResult = permissionManager.hasRole(authStore.user.id, props.roles)
} else if (Array.isArray(props.roles)) {
permissionResult = props.roles.some(role =>
permissionManager.hasRole(authStore.user.id, role)
)
}
}
// 异步验证器
if (permissionResult && props.asyncValidator) {
const validationResult = await props.asyncValidator(
authStore.user,
props.context
)
permissionResult = validationResult.allowed !== false
}
hasPermission.value = permissionResult
} catch (error) {
console.error('权限验证失败:', error)
hasPermission.value = false
} finally {
loading.value = false
}
}
// 监听权限变化
watch(
() => [props.permissions, props.roles, props.context, authStore.user],
checkPermissions,
{ deep: true, immediate: true }
)
return {
loading,
hasPermission
}
}
}
</script>
<style scoped>
.permission-loading {
display: flex;
align-items: center;
gap: 8px;
padding: 16px;
color: #666;
}
.permission-fallback {
padding: 16px;
}
.no-permission {
text-align: center;
color: #999;
}
.no-permission p {
margin: 8px 0 0 0;
}
</style>
🚀 性能优化和最佳实践
权限缓存策略
javascript
// 权限缓存管理器
class PermissionCache {
constructor() {
this.cache = new Map()
this.cacheTimeout = 5 * 60 * 1000 // 5分钟缓存
this.maxCacheSize = 1000
}
// 生成缓存键
generateKey(userId, permission, context = {}) {
const contextStr = JSON.stringify(context)
return `${userId}:${permission}:${contextStr}`
}
// 获取缓存
get(userId, permission, context) {
const key = this.generateKey(userId, permission, context)
const cached = this.cache.get(key)
if (!cached) return null
// 检查是否过期
if (Date.now() - cached.timestamp > this.cacheTimeout) {
this.cache.delete(key)
return null
}
return cached.result
}
// 设置缓存
set(userId, permission, context, result) {
const key = this.generateKey(userId, permission, context)
// 检查缓存大小
if (this.cache.size >= this.maxCacheSize) {
this.cleanup()
}
this.cache.set(key, {
result,
timestamp: Date.now()
})
}
// 清理过期缓存
cleanup() {
const now = Date.now()
const toDelete = []
for (const [key, cached] of this.cache) {
if (now - cached.timestamp > this.cacheTimeout) {
toDelete.push(key)
}
}
toDelete.forEach(key => this.cache.delete(key))
// 如果还是太大,删除最旧的一半
if (this.cache.size >= this.maxCacheSize) {
const entries = Array.from(this.cache.entries())
entries.sort((a, b) => a[1].timestamp - b[1].timestamp)
const toRemove = entries.slice(0, Math.floor(entries.length / 2))
toRemove.forEach(([key]) => this.cache.delete(key))
}
}
// 清空用户缓存
clearUserCache(userId) {
const toDelete = []
for (const key of this.cache.keys()) {
if (key.startsWith(`${userId}:`)) {
toDelete.push(key)
}
}
toDelete.forEach(key => this.cache.delete(key))
}
// 清空所有缓存
clear() {
this.cache.clear()
}
}
// 带缓存的权限验证器
class CachedPermissionValidator extends DynamicPermissionValidator {
constructor(permissionManager) {
super(permissionManager)
this.cache = new PermissionCache()
}
async validate(userId, permission, context = {}) {
// 尝试从缓存获取
const cached = this.cache.get(userId, permission, context)
if (cached !== null) {
return cached
}
// 执行验证
const result = await super.validate(userId, permission, context)
// 缓存结果
this.cache.set(userId, permission, context, result)
return result
}
// 清理用户缓存(用户权限变更时调用)
invalidateUserCache(userId) {
this.cache.clearUserCache(userId)
}
}
路由守卫的性能优化
javascript
// 优化的路由守卫管理器
class OptimizedRouteGuard {
constructor(router, permissionValidator) {
this.router = router
this.validator = permissionValidator
this.guardCache = new Map()
this.setupOptimizedGuards()
}
setupOptimizedGuards() {
// 批量权限检查守卫
this.router.beforeEach(async (to, from, next) => {
const authStore = useAuthStore()
if (!authStore.isAuthenticated) {
return next()
}
// 收集所有需要检查的权限
const permissionsToCheck = this.collectPermissions(to)
if (permissionsToCheck.length === 0) {
return next()
}
try {
// 批量验证权限
const results = await this.validator.validateBatch(
authStore.user.id,
permissionsToCheck,
{ route: to }
)
// 检查是否有被拒绝的权限
const deniedPermissions = Object.entries(results)
.filter(([_, result]) => !result.allowed)
if (deniedPermissions.length > 0) {
return next({
name: 'Forbidden',
params: {
reason: 'insufficient_permission',
details: deniedPermissions
}
})
}
next()
} catch (error) {
console.error('权限验证失败:', error)
next({ name: 'Error', params: { error } })
}
})
// 预加载守卫优化
this.router.beforeEach(async (to, from, next) => {
if (to.meta.preload && this.shouldPreload(to, from)) {
try {
await this.optimizedPreload(to)
} catch (error) {
console.error('预加载失败:', error)
}
}
next()
})
}
// 收集路由需要的所有权限
collectPermissions(route) {
const permissions = new Set()
// 收集当前路由的权限
if (route.meta.permissions) {
route.meta.permissions.forEach(p => permissions.add(p))
}
// 收集父路由的权限
route.matched.forEach(record => {
if (record.meta.permissions) {
record.meta.permissions.forEach(p => permissions.add(p))
}
})
return Array.from(permissions)
}
// 判断是否需要预加载
shouldPreload(to, from) {
// 如果是相同路由的参数变化,可能不需要预加载
if (to.name === from.name && to.meta.preloadOnParamChange === false) {
return false
}
// 检查预加载缓存
const cacheKey = this.getPreloadCacheKey(to)
return !this.guardCache.has(cacheKey)
}
// 优化的预加载
async optimizedPreload(route) {
const cacheKey = this.getPreloadCacheKey(route)
// 检查缓存
if (this.guardCache.has(cacheKey)) {
return this.guardCache.get(cacheKey)
}
// 执行预加载
const preloadPromise = this.executePreload(route)
// 缓存Promise(避免重复请求)
this.guardCache.set(cacheKey, preloadPromise)
try {
const result = await preloadPromise
// 缓存结果
this.guardCache.set(cacheKey, Promise.resolve(result))
return result
} catch (error) {
// 移除失败的缓存
this.guardCache.delete(cacheKey)
throw error
}
}
getPreloadCacheKey(route) {
return `${route.name}-${JSON.stringify(route.params)}`
}
async executePreload(route) {
const preloadConfig = route.meta.preload
if (typeof preloadConfig === 'function') {
return await preloadConfig(route)
}
if (Array.isArray(preloadConfig)) {
return await Promise.all(
preloadConfig.map(loader => loader(route))
)
}
return null
}
// 清理缓存
clearCache() {
this.guardCache.clear()
}
}
📝 总结
Vue Router的路由守卫与权限控制系统是构建企业级应用的重要基础设施。通过本文的学习,你应该掌握了:
核心概念:
- 路由守卫的设计理念和执行机制
- 全局守卫、路由守卫、组件守卫的应用场景
- RBAC权限模型的设计和实现原理
实践技能:
- 企业级权限控制系统的构建
- 动态权限验证和角色管理
- 组件级权限控制的实现方法
高级应用:
- 权限缓存和性能优化策略
- 复杂权限规则的动态验证
- 路由守卫的批量优化技术
最佳实践:
- 权限系统的架构设计原则
- 安全性和用户体验的平衡
- 大型应用的权限管理策略
掌握这些知识将帮助你构建安全、高效的Vue 3应用权限系统,特别是在处理复杂的企业级权限需求时。在下一篇文章中,我们将学习Pinia状态管理的深度应用。