问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Vue 3 使用路由守卫进行鉴权

创作时间:
作者:
@小白创作中心

Vue 3 使用路由守卫进行鉴权

引用
CSDN
1.
https://m.blog.csdn.net/qq_16242613/article/details/145148313

1. 引言

为什么需要路由守卫?

在现代 Web 应用中,用户权限管理是一个非常重要的功能。例如,某些页面只允许登录用户访问,而某些页面则需要对用户的角色进行更细粒度的控制。为了实现这些功能,我们需要在用户访问特定页面之前进行鉴权。

Vue Router 提供了路由守卫(Route Guards)功能,允许我们在路由跳转之前、之后或解析过程中执行自定义逻辑。通过路由守卫,我们可以轻松实现鉴权功能,确保只有授权用户才能访问特定页面。

路由守卫的应用场景

  • 登录验证:确保用户已登录后才能访问受保护的页面。
  • 角色权限控制:根据用户的角色限制其访问权限。
  • 数据预加载:在进入某个页面之前预加载所需数据。
  • 页面访问日志:记录用户的页面访问行为。

2. Vue 3 和 Vue Router 简介

Vue 3 的核心特性

Vue 3 是 Vue.js 的最新版本,带来了许多新特性:

  • Composition API:更灵活的逻辑复用方式。
  • 更好的 TypeScript 支持:Vue 3 完全使用 TypeScript 重写。
  • 性能优化:更快的渲染速度和更小的包体积。

Vue Router 的基本用法

Vue Router 是 Vue.js 的官方路由管理器,用于构建单页面应用(SPA)。以下是一个简单的 Vue Router 配置示例:

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('@/views/About.vue'),
  },
];
const router = createRouter({
  history: createWebHistory(),
  routes,
});
export default router;

3. 路由守卫的类型

全局前置守卫 (beforeEach)

在路由跳转之前执行,常用于鉴权。

router.beforeEach((to, from, next) => {
  // 鉴权逻辑
  next();
});

全局解析守卫 (beforeResolve)

在路由被解析之前执行,适用于需要等待异步数据加载的场景。

router.beforeResolve((to, from, next) => {
  // 数据预加载逻辑
  next();
});

全局后置守卫 (afterEach)

在路由跳转之后执行,适用于页面访问日志记录等场景。

router.afterEach((to, from) => {
  // 页面访问日志记录
});

路由独享守卫 (beforeEnter)

在某个特定路由配置中定义,仅对该路由生效。

{
  path: '/admin',
  name: 'Admin',
  component: () => import('@/views/Admin.vue'),
  beforeEnter: (to, from, next) => {
    // 鉴权逻辑
    next();
  },
}

组件内守卫 (beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave)

在组件内定义,控制组件的访问和离开。

export default {
  beforeRouteEnter(to, from, next) {
    // 组件进入前的逻辑
    next();
  },
  beforeRouteUpdate(to, from, next) {
    // 组件更新时的逻辑
    next();
  },
  beforeRouteLeave(to, from, next) {
    // 组件离开时的逻辑
    next();
  },
};

4. 实现鉴权的基本思路

什么是鉴权?

鉴权是指验证用户是否有权限访问某个资源。在 Web 应用中,通常通过以下方式实现鉴权:

  • 登录验证:检查用户是否已登录。
  • 角色权限控制:根据用户的角色限制其访问权限。

鉴权的常见方式

  • 前端鉴权:通过路由守卫控制页面访问权限。
  • 后端鉴权:通过 API 接口验证用户权限。

5. 实战:使用路由守卫进行鉴权

项目初始化

使用 Vue CLI 或 Vite 创建一个新的 Vue 3 项目:

npm create vite@latest my-vue-app --template vue-ts
cd my-vue-app
npm install

定义路由和元信息

router/index.ts 中定义路由,并为需要鉴权的路由添加 meta 字段。

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
    meta: { requiresAuth: false },
  },
  {
    path: '/dashboard',
    name: 'Dashboard',
    component: () => import('@/views/Dashboard.vue'),
    meta: { requiresAuth: true },
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/Login.vue'),
    meta: { requiresAuth: false },
  },
];
const router = createRouter({
  history: createWebHistory(),
  routes,
});
export default router;

实现全局前置守卫

router/index.ts 中使用 beforeEach 钩子进行鉴权。

import { RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
router.beforeEach(
  (
    to: RouteLocationNormalized,
    from: RouteLocationNormalized,
    next: NavigationGuardNext
  ) => {
    const isAuthenticated = checkAuth(); // 检查用户是否登录
    const requiresAuth = to.meta.requiresAuth; // 判断目标路由是否需要鉴权
    if (requiresAuth && !isAuthenticated) {
      // 如果需要鉴权且用户未登录,跳转到登录页
      next({ name: 'Login' });
    } else if (to.name === 'Login' && isAuthenticated) {
      // 如果用户已登录但尝试访问登录页,跳转到首页
      next({ name: 'Home' });
    } else {
      // 其他情况,允许访问
      next();
    }
  }
);
// 模拟检查用户是否登录的函数
function checkAuth(): boolean {
  return !!localStorage.getItem('token');
}

结合 Pinia 或 Vuex 进行状态管理

如果使用 Pinia 或 Vuex 管理用户登录状态,可以在路由守卫中从 Store 中获取登录状态。

Pinia 示例

import { useAuthStore } from '@/stores/auth';
router.beforeEach((to, from, next) => {
  const authStore = useAuthStore();
  const requiresAuth = to.meta.requiresAuth;
  if (requiresAuth && !authStore.isAuthenticated) {
    next({ name: 'Login' });
  } else if (to.name === 'Login' && authStore.isAuthenticated) {
    next({ name: 'Home' });
  } else {
    next();
  }
});

Vuex 示例

import store from '@/store';
router.beforeEach((to, from, next) => {
  const requiresAuth = to.meta.requiresAuth;
  const isAuthenticated = store.getters.isAuthenticated;
  if (requiresAuth && !isAuthenticated) {
    next({ name: 'Login' });
  } else if (to.name === 'Login' && isAuthenticated) {
    next({ name: 'Home' });
  } else {
    next();
  }
});

处理登录和登出逻辑

在登录和登出时更新用户的登录状态。

// 登录成功后保存 token
localStorage.setItem('token', 'your-auth-token');
router.push({ name: 'Dashboard' });
// 登出时清除 token
localStorage.removeItem('token');
router.push({ name: 'Login' });

6. 进阶:动态路由和权限控制

动态路由的实现

动态路由是指根据用户权限动态生成路由表。例如,管理员和普通用户看到的路由可能不同。

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
  },
  {
    path: '/admin',
    name: 'Admin',
    component: () => import('@/views/Admin.vue'),
    meta: { requiresAuth: true, roles: ['admin'] },
  },
  {
    path: '/user',
    name: 'User',
    component: () => import('@/views/User.vue'),
    meta: { requiresAuth: true, roles: ['user'] },
  },
];

在路由守卫中根据用户角色动态生成路由:

router.beforeEach((to, from, next) => {
  const userRole = getUserRole(); // 获取用户角色
  const requiredRoles = to.meta.roles; // 获取目标路由所需的角色
  if (requiredRoles && !requiredRoles.includes(userRole)) {
    next({ name: 'Forbidden' }); // 如果用户角色不符合要求,跳转到无权限页面
  } else {
    next();
  }
});

基于角色的权限控制

通过 meta 字段定义路由所需的角色,并在路由守卫中进行验证。

{
  path: '/admin',
  name: 'Admin',
  component: () => import('@/views/Admin.vue'),
  meta: { requiresAuth: true, roles: ['admin'] },
}

7. 常见问题与解决方案

路由守卫的死循环问题

如果路由守卫逻辑不正确,可能会导致死循环。例如,未登录用户尝试访问受保护页面时,被重定向到登录页,而登录页又重定向到其他页面。

解决方案:确保在路由守卫中正确处理重定向逻辑。

如何处理未定义的路由?

如果用户访问了一个未定义的路由,可以跳转到 404 页面。

{
  path: '/:pathMatch(.*)*',
  name: 'NotFound',
  component: () => import('@/views/NotFound.vue'),
}

路由守卫的性能优化

如果路由守卫逻辑复杂,可能会影响页面加载性能。

解决方案:将复杂的逻辑拆分为异步函数,或使用缓存机制。

8. 总结与展望

路由守卫的最佳实践

  • 明确鉴权逻辑:确保路由守卫的逻辑清晰易懂。
  • 避免死循环:正确处理重定向逻辑。
  • 结合状态管理:使用 Pinia 或 Vuex 管理用户登录状态。

未来发展方向

  • 更细粒度的权限控制:支持更复杂的权限模型。
  • 动态路由生成:根据用户权限动态生成路由表。

通过本文的学习,你应该已经掌握了如何在 Vue 3 中使用路由守卫进行鉴权。希望这些内容能帮助你在实际项目中更好地实现用户权限管理功能!

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号