Vue3从入门到精通: 4.2 Vue Router路由守卫与权限控制深度解析

👋 大家好,我是 阿问学长!专注于分享优质开源项目解析、毕业设计项目指导支持、幼小初高教辅资料推荐等,欢迎关注交流!🚀

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状态管理的深度应用。