如何在Vue的beforeEach路由守卫中基于Firebase v9实现登录态校验
问题根源
- 你封装的
userAuthState是同步返回逻辑,而Firebase的onAuthStateChanged是异步回调方法,回调执行前函数就已经返回了初始值null,且该方法没有返回Promise,加await也不会生效。 - 路由守卫逻辑存在两处错误:一是
await !userAuthState()的写法优先级错误,!优先级高于await,会先对返回的null取反得到true再await,导致判断逻辑完全失效;二是每次守卫执行重复调用两次鉴权方法,且错误判断会触发反复跳转形成死循环,导致console.log重复打印、页面无法正常跳转。
正确实现方案
第一步:修正鉴权状态封装方法
将方法改造为返回Promise,同时添加状态缓存避免重复监听造成内存泄漏:
// src/backend/firebase-config.js import { onAuthStateChanged } from "firebase/auth"; import { auth } from "./你的firebase初始化配置路径"; // 全局缓存用户状态,避免重复监听 let cachedUser = null; export const getUserAuthState = () => { return new Promise((resolve) => { // 已有缓存直接返回,减少性能消耗 if (cachedUser !== null) { return resolve(cachedUser); } // 监听auth状态变更,拿到结果后取消监听 const unsubscribe = onAuthStateChanged(auth, (user) => { cachedUser = user || null; unsubscribe(); resolve(cachedUser); }); }); };
第二步:修正路由全局前置守卫逻辑
单次获取用户状态后再做判断,避免死循环:
import { createRouter, createWebHistory } from 'vue-router' import { getUserAuthState } from 'src/backend/firebase-config'; // 路由配置示例,注意meta参数的定义 const routes = [ { path: '/login', component: () => import('@/views/Login.vue'), meta: { requiresAuth: 'login' } // 登录页标记 }, { path: '/dashboard', component: () => import('@/views/Dashboard.vue'), meta: { requiresAuth: true } // 需要登录鉴权的页面标记 }, { path: '/', component: () => import('@/views/Home.vue') } ] const Router = createRouter({ history: createWebHistory(), routes }) Router.beforeEach(async (to, from, next) => { // 单次获取用户状态,避免重复调用 const currentUser = await getUserAuthState(); // 访问需要鉴权的页面且用户未登录,跳转登录页 if (to.meta.requiresAuth === true && !currentUser) { next({ path: '/login', query: { redirect: to.fullPath } }) } // 访问登录页且用户已登录,跳转首页 else if (to.meta.requiresAuth === 'login' && currentUser) { next({ path: '/' }) } // 其余场景正常放行 else { next() } }) export default Router
补充说明
如果项目中使用了Pinia/Vuex等状态管理工具,可以将获取到的用户状态存入全局store共享,后续业务逻辑无需重复调用鉴权方法。
内容的提问来源于stack exchange,提问作者ibrahim farhat
相关产品推荐
相关产品推荐

