You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Vue Router全局导航守卫实现多条件路由鉴权跳转

Vue3+Pinia 路由鉴权(含账号验证状态拦截)实现方案

核心实现思路

由于登录接口仅返回accessToken,账号验证状态需要通过受保护接口获取,因此路由拦截分三层判断:

  • 本地无有效token:直接重定向到登录页
  • 本地有token但未拉取过用户验证状态:先调用接口获取用户信息,拿到verified状态后再做跳转判断
  • 本地有token且已获取验证状态:根据verified值判断跳转验证页还是仪表盘

具体实现步骤

第一步:新增Pinia用户状态Store

全局存储token、账号验证状态、用户信息加载标记,避免重复请求接口,保证全应用状态同步。
新建src/stores/user.js文件,代码如下:

import { defineStore } from 'pinia'
import axios from 'axios'

export const useUserStore = defineStore('user', {
  state: () => ({
    accessToken: localStorage.getItem('accessToken') || '',
    isVerified: false,
    // 标记是否已拉取过用户信息,避免路由跳转重复请求接口
    userInfoLoaded: false
  }),
  actions: {
    // 拉取用户信息(含账号验证状态,直接复用你现有的dashboard接口即可)
    async fetchUserInfo() {
      if (!this.accessToken) return
      try {
        const res = await axios.get('https://some-api-url/dashboard', {
          headers: {
            Authorization: `Bearer ${this.accessToken}`
          }
        })
        // 按接口实际返回的字段取verified值
        this.isVerified = res.data.data.user.verified
        this.userInfoLoaded = true
      } catch (err) {
        // token失效时清空本地认证状态
        if (err.response?.status === 401) {
          this.clearAuth()
        }
        throw err
      }
    },
    setToken(token) {
      this.accessToken = token
      localStorage.setItem('accessToken', token)
      // 存入新token后重置加载标记,下次路由跳转重新拉取用户信息
      this.userInfoLoaded = false
      this.isVerified = false
    },
    clearAuth() {
      this.accessToken = ''
      this.isVerified = false
      this.userInfoLoaded = false
      localStorage.removeItem('accessToken')
    }
  }
})

第二步:调整路由配置+重写全局前置守卫

给路由加差异化meta标记:游客可访问页、仅需登录页、需登录+验证页,守卫里分层判断权限。
修改router/index.js代码如下:

import { createRouter, createWebHistory } from 'vue-router'
// 按你的实际文件路径引入userStore
import { useUserStore } from '@/stores/user'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: "/signin",
      name: "signin",
      component: () => import("../views/SignIn.vue"),
      meta: { guestOnly: true } // 标记仅游客可访问,已登录用户禁止进入
    },
    {
      path: "/verify",
      name: "verify",
      component: () => import("../views/Verification.vue"),
      meta: { needsAuth: true } // 仅需登录,不需要账号验证
    },
    {
      path: "/dashboard",
      name: "dashboard",
      component: () => import("../views/UserDashboard.vue"),
      meta: { needsAuth: true, requiresVerified: true } // 需要登录+账号已验证
    },
    // 根路径默认重定向
    {
      path: '/',
      redirect: () => {
        const userStore = useUserStore()
        if (!userStore.accessToken) return '/signin'
        if (!userStore.isVerified) return '/verify'
        return '/dashboard'
      }
    }
  ]
})

router.beforeEach(async (to, from, next) => {
  const userStore = useUserStore()
  const hasToken = !!userStore.accessToken

  // 1. 访问需鉴权页面但无token,直接跳登录
  if (to.meta.needsAuth && !hasToken) {
    return next({ name: 'signin' })
  }

  // 2. 已登录用户访问游客专属页(比如登录页),按验证状态跳对应页面
  if (to.meta.guestOnly && hasToken) {
    if (!userStore.userInfoLoaded) {
      await userStore.fetchUserInfo()
    }
    return next(userStore.isVerified ? { name: 'dashboard' } : { name: 'verify' })
  }

  // 3. 有token但未拉取过用户信息,先拉取再判断权限
  if (hasToken && !userStore.userInfoLoaded) {
    try {
      await userStore.fetchUserInfo()
    } catch (err) {
      // 拉取失败(如token过期)已在store中清空状态,直接跳登录
      return next({ name: 'signin' })
    }
  }

  // 4. 访问需验证的页面但账号未验证,跳验证页
  if (to.meta.requiresVerified && !userStore.isVerified) {
    return next({ name: 'verify' })
  }

  // 5. 已验证用户访问验证页,直接跳仪表盘
  if (to.name === 'verify' && userStore.isVerified) {
    return next({ name: 'dashboard' })
  }

  next()
})

export default router

第三步:修改登录方法逻辑

登录成功后不要硬编码跳仪表盘,交给路由守卫自动判断跳转目标,同时用store方法存token保证状态同步。
修改loginUser方法代码如下:

// 组件setup中先引入userStore
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()

const loginUser = async () => {
  try {
    const res = await axios.post(
      "https://some-api-url/login",
      signin.value,
      {
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
      }
    );

    // 调用store方法存token,自动重置用户信息加载状态
    userStore.setToken(res.data.data.accessToken);

    // 跳根路径,由守卫自动判断跳转verify还是dashboard
    router.push("/");
  } catch (error) {
    const errMsg = error.response?.data?.message || '登录失败,请重试'
    alert(errMsg);
  }
};

补充规则说明

  • 后续新增页面时,仅需登录即可访问的页面加meta: { needsAuth: true }
  • 需要账号完成验证才能访问的页面加meta: { needsAuth: true, requiresVerified: true }
  • 用户完成账号验证操作后,直接将store中的isVerified设为true,再调用router.push('/dashboard')即可正常跳转
  • userInfoLoaded标记会避免每次路由跳转都重复请求用户信息接口,仅在首次加载、token更新时触发拉取

内容的提问来源于stack exchange,提问作者Mena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:27:13