Skip to content

Vue3 动态路由与路由守卫实现

1. 项目背景

在中后台管理系统中,不同角色的用户需要看到不同的菜单和访问不同的页面。为了实现这个需求,我们需要通过动态路由和路由守卫来控制用户的访问权限。

2. 技术实现

2.1 核心依赖

  • Vue Router
  • Pinia(状态管理)
  • NProgress(进度条)

2.2 实现思路

  1. 设置路由白名单
  2. 配置全局路由守卫
  3. 根据用户角色动态判断路由权限
  4. 处理路由跳转逻辑

2.3 具体实现

2.3.1 路由守卫配置

javascript
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { useLoginStore } from '@/store/modules/userlogin'
import { roleRoutes } from './permission'

const whiteList = ['/login']

export function setupRouterGuard(router) {
  // 配置进度条
  NProgress.configure({ showSpinner: false })

  // 路由前置守卫
  router.beforeEach(async (to, from, next) => {
    const store = useLoginStore()
    
    NProgress.start()
    
    const token = store.token
    const message = store.message
    
    if (message === '登录凭证失效' || !token) {
      // 如果要去的页面在白名单中,则直接放行
      if (whiteList.includes(to.path)) {
        next()
      } else {
        // 否则,重定向到登录页面,并携带要去的页面路径,登录成功后,会重定向到要去的页面
        next({
          path: '/login',
          query: { redirect: to.fullPath }
        })
      }
    } else if (token) {
      // 获取用户角色并解析
      const userRoles = JSON.parse(localStorage.getItem('userInfo')).split(',')
      // 检查用户是否有权限访问要去的页面
      const hasPermission = checkRoutePermission(to.path, userRoles)
      // 如果没有权限,则阻止访问
      if (!hasPermission) {
        NProgress.done()
        return next(false)
      }
      
      if (to.path === '/login') {
        // 如果有重定向参数就跳转到保存的路由,否则跳转到默认页面
        const redirect = to.query.redirect
        next(redirect || '/DefaultContent')
      } else if (to.path === '/') {
        // 根据角色决定默认页面
        const defaultPath = '/DefaultContent'
        next(defaultPath)
      } else {
        next()
      }
    } else {
      if (whiteList.includes(to.path)) {
        next()
      } else {
        next('/login')
      }
    }
    NProgress.done()   // 结束进度条
  })

  // 路由后置守卫
  router.afterEach(() => {
    NProgress.done()   // 结束进度条
  })

  // 路由错误处理
  router.onError((error) => {
    console.error('路由错误:', error)
    NProgress.done()   // 结束进度条
  })
}

2.3.2 权限检查函数

javascript
// 修改权限检查函数以支持多角色
function checkRoutePermission(path, roles) {
  // 如果用户有任何一个角色具有权限,就允许访问
  return roles.some(role => {
    if (role === '平台管理员' || roleRoutes[role] === 'all') {
      return true
    }
    return roleRoutes[role]?.includes(path)
  })
}

3. 核心功能解析

3.1 路由守卫功能

  1. 进度条处理:使用 NProgress 在路由切换时显示进度条
  2. 登录状态检查:检查 token 和登录状态
  3. 权限控制:根据用户角色控制页面访问权限
  4. 路由重定向:处理登录后的重定向逻辑

3.2 权限控制逻辑

  1. 多角色支持:用户可以拥有多个角色
  2. 白名单机制:某些路由无需登录即可访问
  3. 平台管理员特权:平台管理员拥有所有路由访问权限
  4. 角色路由映射:通过 roleRoutes 配置不同角色可访问的路由

4. 重点

4.1 技术要点

  1. 如何实现动态路由?

    • 通过路由守卫 beforeEach 控制路由访问
    • 根据用户角色动态判断权限
    • 使用路由元信息存储权限信息
  2. 权限控制的实现方式?

    • 基于角色的访问控制(RBAC)
    • 使用路由守卫进行权限判断
    • 支持多角色权限叠加
  3. 登录状态管理?

    • 使用 Pinia 管理登录状态
    • token 存储和验证
    • 登录失效处理

4.2 性能优化

  1. 路由懒加载
  2. 权限判断缓存
  3. 进度条优化

4.3 安全考虑

  1. 前端权限控制只是辅助,后端也需要进行权限验证
  2. token 安全存储
  3. 敏感信息加密处理

5. 项目优化建议

  1. 可以考虑使用路由元信息(meta)存储权限信息
  2. 实现路由权限的缓存机制
  3. 添加更细粒度的权限控制
  4. 优化路由切换的性能

6. 总结

动态路由和权限控制是中后台项目的重要组成部分,通过合理的路由守卫配置和权限判断逻辑,可以实现灵活的权限控制系统。在实际项目中,需要根据具体需求进行定制和优化。