Vue导航守卫中获取共享服务实现登录校验的最优方案(对标Angular)
刚好我之前也处理过类似的场景,给你梳理下Vue里实现和Angular Route Guard相同登录校验功能的几种靠谱方案,按推荐度排序:
1. 使用Pinia/Vuex(官方推荐,最适合中大型项目)
Vue官方的状态管理方案(Vue3用Pinia,Vue2用Vuex)天生就是用来管理全局共享状态的,比如用户登录信息,完美替代Angular里的共享服务,而且在导航守卫里可以直接调用,非常方便。
举个Pinia的例子:
首先定义一个用户状态的store:
// stores/auth.ts import { defineStore } from 'pinia' export const useAuthStore = defineStore('auth', { state: () => ({ user: null // 存储登录后的用户数据 }), actions: { // 登录成功后调用这个方法设置用户信息 setUser(userData) { this.user = userData // 可选:把用户信息存在localStorage做持久化 localStorage.setItem('currentUser', JSON.stringify(userData)) }, // 初始化时从本地存储恢复用户信息 initUser() { const savedUser = localStorage.getItem('currentUser') if (savedUser) { this.user = JSON.parse(savedUser) } } } })
然后在路由守卫里使用这个store:
// router/index.ts import { createRouter, createWebHistory } from 'vue-router' import { useAuthStore } from '@/stores/auth' const router = createRouter({ history: createWebHistory(), routes: [ { path: '/login', component: () => import('@/views/Login.vue') }, // 需要登录才能访问的路由,加上meta标记 { path: '/dashboard', component: () => import('@/views/Dashboard.vue'), meta: { requiresAuth: true } } ] }) // 全局前置守卫,统一处理登录校验 router.beforeEach((to, from, next) => { const authStore = useAuthStore() // 先初始化用户状态(比如刷新页面后恢复) if (!authStore.user) { authStore.initUser() } // 判断当前路由是否需要登录,且用户未登录时跳转到登录页 if (to.meta.requiresAuth && !authStore.user) { next('/login') } else { next() } }) export default router
这种方案的好处是状态管理更规范,支持响应式,复杂项目里后续扩展权限、角色校验也更方便。
2. 自定义单例服务(适合小型项目,轻量无依赖)
如果你的项目很小,不想引入状态管理库,也可以自己创建一个单例服务,直接在导航守卫里导入使用,不用绑定到Vue.prototype(之前绑定失败是因为导航守卫执行时Vue实例还没创建,拿不到原型上的属性)。
先创建单例服务:
// services/authService.ts class AuthService { private _user: any = null constructor() { // 初始化时从本地存储恢复用户信息 const savedUser = localStorage.getItem('currentUser') if (savedUser) { this._user = JSON.parse(savedUser) } } get user() { return this._user } setUser(userData: any) { this._user = userData localStorage.setItem('currentUser', JSON.stringify(userData)) } clearUser() { this._user = null localStorage.removeItem('currentUser') } } // 导出单例,整个项目里只会创建一次实例 export default new AuthService()
然后在路由守卫里直接导入使用:
// router/index.ts import { createRouter, createWebHistory } from 'vue-router' import authService from '@/services/authService' const router = createRouter({ // 路由定义和上面类似 }) router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !authService.user) { next('/login') } else { next() } })
这种方案轻量灵活,不用额外依赖,小型项目里足够用。
3. Vue3的provide/inject(适合组件场景,守卫里也能凑合用)
如果你用的是Vue3,也可以用provide/inject来共享服务,但因为导航守卫不在组件树里,需要从app实例上获取注入的服务,步骤稍繁琐:
首先在main.ts里提供服务:
// main.ts import { createApp } from 'vue' import App from './App.vue' import authService from '@/services/authService' import router from '@/router' const app = createApp(App) // 提供全局服务 app.provide('authService', authService) app.use(router) app.mount('#app')
然后在路由守卫里获取:
// router/index.ts import { getCurrentInstance } from 'vue' router.beforeEach((to, from, next) => { const appInstance = getCurrentInstance() // 从app上下文里获取注入的服务 const authService = appInstance?.appContext.provides['authService'] if (to.meta.requiresAuth && !authService?.user) { next('/login') } else { next() } })
不过这种方法不如前两种直接,更适合组件内部使用,守卫里还是优先推荐前两种方案。
内容的提问来源于stack exchange,提问作者Alex Herman
相关产品推荐
相关产品推荐

