🎯 什么是路由导航守卫?
路由导航守卫是Vue Router提供的控制路由跳转的机制,允许我们在路由跳转前或跳转后执行一些逻辑。最常见的应用场景就是身份验证和权限控制。
🚪 导航守卫类型
Vue Router提供了三种守卫:
全局前置守卫:
router.beforeEach()全局后置守卫:
router.afterEach()路由独享守卫:在路由配置中定义
🔐 全局前置守卫示例
基础身份验证实现
import { createRouter, createWebHashHistory } from "vue-router";
// 导入页面组件
import Login from "../components/Login.vue";
import Table from "../components/table.vue";
import Menu from "../components/menu.vue";
import View from "../views/view.vue";
import Upload from "../components/menu_content/Upload.vue";
import Search from "../components/menu_content/Search.vue";
import ArrangeRoom from "../components/menu_content/arrange_room.vue";
// 定义路由配置
const routes = [
{
path: '/login',
name: 'login',
component: Login,
meta: { requiresAuth: false }
},
{
path: '/',
name: 'home',
component: View,
meta: { requiresAuth: true }
},
{
path: '/table',
name: 'table',
component: Table,
meta: { requiresAuth: true }
},
{
path: '/menu',
name: 'menu',
component: Menu,
meta: { requiresAuth: true }
},
{
path: '/upload',
name: 'upload',
component: Upload,
meta: { requiresAuth: true }
},
{
path: '/search',
name: 'search',
component: Search,
meta: { requiresAuth: true }
},
{
path: '/arrange-room',
name: 'arrangeRoom',
component: ArrangeRoom,
meta: { requiresAuth: true }
}
];
// 创建路由实例
const router = createRouter({
history: createWebHashHistory(),
routes,
});
// 全局前置守卫
router.beforeEach((to, from, next) => {
const token = localStorage.getItem("token");
// 检查路由是否需要身份验证
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
// 如果需要验证且没有token,跳转到登录页
if (requiresAuth && !token) {
next({ name: 'login' });
console.log("导航守卫失败,跳到登录页");
return;
}
// 如果已经登录且访问登录页,可以重定向到首页
if (token && to.name === 'login') {
next({ name: 'home' });
console.log("已登录用户访问登录页,重定向到首页");
return;
}
// 其他情况允许继续导航
next();
console.log("导航守卫成功,继续");
});
export default router;🔄 完整的导航守卫实现
结合token验证和权限管理
import { createRouter, createWebHashHistory } from "vue-router";
const router = createRouter({
history: createWebHashHistory(),
routes: [
// 公开路由
{
path: '/login',
name: 'login',
component: () => import('../components/Login.vue'),
meta: {
requiresAuth: false,
title: '登录'
}
},
{
path: '/register',
name: 'register',
component: () => import('../components/Register.vue'),
meta: { requiresAuth: false }
},
// 需要验证的路由
{
path: '/dashboard',
name: 'dashboard',
component: () => import('../views/Dashboard.vue'),
meta: {
requiresAuth: true,
roles: ['admin', 'user']
}
},
{
path: '/admin',
name: 'admin',
component: () => import('../views/Admin.vue'),
meta: {
requiresAuth: true,
roles: ['admin'] // 只有管理员可以访问
}
}
],
});
// 前置守卫
router.beforeEach(async (to, from, next) => {
// 设置页面标题
if (to.meta.title) {
document.title = to.meta.title;
}
const token = localStorage.getItem("token");
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
// 1. 检查是否需要身份验证
if (requiresAuth) {
if (!token) {
// 没有token,跳转登录
next({
name: 'login',
query: { redirect: to.fullPath } // 保存目标路径
});
return;
}
// 2. 检查用户权限(如果需要)
if (to.meta.roles) {
const userRole = localStorage.getItem("userRole");
if (!userRole || !to.meta.roles.includes(userRole)) {
// 权限不足
next({ name: 'unauthorized' }); // 跳转到无权限页面
return;
}
}
}
// 3. 已登录用户访问登录页,重定向到首页
if (token && to.name === 'login') {
next({ name: 'dashboard' });
return;
}
// 4. 允许导航
next();
});
// 后置守卫
router.afterEach((to, from) => {
// 页面跳转后的处理
console.log(`从 ${from.path} 跳转到 ${to.path}`);
// 可以在这里添加统计代码、进度条结束等
// hideProgress();
// trackPageView(to.path);
});
export default router;import
🛡️ 导航守卫与拦截器的配合
双重验证机制
// router.js - 路由守卫处理基础验证
router.beforeEach((to, from, next) => {
const token = localStorage.getItem("token");
if (to.name !== "login" && !token) {
next({ name: "login" });
return;
}
next();
});
// request.js - 请求拦截器处理详细验证
import axios from "axios";
const request = axios.create();
request.interceptors.request.use(config => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
request.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
// token无效,清除并跳转登录
localStorage.removeItem("token");
window.location.href = '/login';
}
return Promise.reject(error);
}
);💡 实用技巧和最佳实践
1. 动态添加路由
// 根据用户权限动态添加路由
function addDynamicRoutes(userRole) {
if (userRole === 'admin') {
router.addRoute({
path: '/admin-panel',
name: 'adminPanel',
component: () => import('../views/AdminPanel.vue')
});
}
}2. 路由进度条
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
router.beforeEach(() => {
NProgress.start();
});
router.afterEach(() => {
NProgress.done();
});3. 路由缓存控制
router.beforeEach((to, from, next) => {
// 处理页面缓存
if (to.meta.keepAlive) {
to.meta.$keepAlive = true;
}
next();
});⚠️ 注意事项
避免死循环:确保守卫逻辑不会导致无限重定向
异步处理:守卫中如果需要异步操作,要正确处理Promise
权限更新:用户权限变更时要重新验证路由
错误处理:合理处理守卫中的异常情况
📝 总结
路由导航守卫是Vue应用安全的重要组成部分,它与axios拦截器配合使用:
🚪 路由守卫:控制页面访问权限(前端验证)
🛡️ 请求拦截器:验证API调用权限(后端验证)
🔄 响应拦截器:处理token过期等异常情况