Nuxt3 Firebase Auth中间件刷新后无法识别已登录用户问题
解决Nuxt3中Firebase Auth页面刷新时路由中间件误判登录状态的问题
在Nuxt3项目中使用Firebase Auth做身份验证,我写了下面的路由中间件来保护需要授权的路由:
export default defineNuxtRouteMiddleware((to, from) => { const { $auth } = useNuxtApp(); const { $localePath } = useNuxtApp(); if(!$auth?.currentUser?.uid){ return navigateTo({ path: $localePath({name: 'auth-login'}) }); } });
初始使用一切正常,登录后能正常导航,但刷新浏览器时,明明用户没退出,还是会被重定向到登录页——此时$auth?.currentUser?.uid返回null。我已经把登录用户数据存在firebaseUser状态里了,可在中间件里获取状态时还是一样的问题:中间件判定未登录并重定向,但状态里明明还存着用户数据。
想问下怎么让这个中间件在页面刷新时正确检测用户的登录状态?
以下是我用到的相关代码:
Firebase Auth插件代码
import { initializeApp } from "firebase/app" import { getAuth } from "firebase/auth" export default defineNuxtPlugin(nuxtApp => { const firebaseConfig = { apiKey: process.env.FIREBASE_API_KEY, authDomain: process.env.FIREBASE_AUTH_DOMAIN, projectId: process.env.FIREBASE_PROJCT_ID, storageBucket: process.env.FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, appId: process.env.FIREBASE_MESSAGING_SENDER_ID, measurementId: process.env.FIREBASE_MEASURMENT_ID, }; // Initialize Firebase const app = initializeApp(firebaseConfig); // Init user initUser(); // Get auth const auth = getAuth(); nuxtApp.vueApp.provide('auth', auth); nuxtApp.provide('auth', auth); })
useFirebase中的initUser逻辑
export const initUser = async () => { const auth = getAuth(); const firebaseUser = useFirebaseUser(); firebaseUser.value = auth.currentUser; onAuthStateChanged(auth, (user) => { firebaseUser.value = user; }); }
状态管理代码
export const useFirebaseUser = () => useState('firebaseUser', () =>{});
核心问题原因
页面刷新时,Firebase Auth需要时间从本地缓存恢复用户会话,而路由中间件是同步执行的,此时auth.currentUser还未初始化完成,所以返回null导致误判。另外initUser里的onAuthStateChanged是异步监听,中间件执行时这个监听还没触发,状态也没更新。
修复方案
1. 把中间件改成异步,等待Auth状态初始化
export default defineNuxtRouteMiddleware(async (to, from) => { const { $auth } = useNuxtApp(); const { $localePath } = useNuxtApp(); const firebaseUser = useFirebaseUser(); // 封装Promise等待Auth状态就绪 const waitForAuth = () => new Promise((resolve) => { const unsubscribe = $auth.onAuthStateChanged((user) => { unsubscribe(); // 完成后取消监听 resolve(user); }); }); const user = await waitForAuth(); firebaseUser.value = user; // 同步状态 if(!user?.uid){ return navigateTo({ path: $localePath({name: 'auth-login'}) }); } });
2. 优化initUser的初始化逻辑
export const initUser = async () => { const auth = getAuth(); const firebaseUser = useFirebaseUser(); // 先同步当前已有状态 firebaseUser.value = auth.currentUser; // 如果已有用户直接返回,无需等待监听 if (firebaseUser.value) return; // 等待Auth状态变化完成 await new Promise((resolve) => { const unsubscribe = auth.onAuthStateChanged((user) => { firebaseUser.value = user; unsubscribe(); resolve(); }); }); }
3. 插件初始化时等待用户状态就绪
修改Firebase Auth插件,让initUser异步执行并等待完成:
import { initializeApp } from "firebase/app" import { getAuth } from "firebase/auth" export default defineNuxtPlugin(async (nuxtApp) => { // 改为async函数 const firebaseConfig = { apiKey: process.env.FIREBASE_API_KEY, authDomain: process.env.FIREBASE_AUTH_DOMAIN, projectId: process.env.FIREBASE_PROJCT_ID, storageBucket: process.env.FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, appId: process.env.FIREBASE_MESSAGING_SENDER_ID, measurementId: process.env.FIREBASE_MEASURMENT_ID, }; // Initialize Firebase const app = initializeApp(firebaseConfig); // 等待用户状态初始化完成 await initUser(); // Get auth const auth = getAuth(); nuxtApp.vueApp.provide('auth', auth); nuxtApp.provide('auth', auth); })
额外注意点
- 不要直接在中间件中依赖
auth.currentUser,它是同步值,刷新时无法立即获取到缓存的用户会话 - 始终利用
onAuthStateChanged的异步特性确保拿到最新用户状态 - 如果使用Nuxt SSR模式,Firebase Auth在服务端无法获取客户端会话,需要用
process.client判断,仅在客户端执行身份验证逻辑
内容的提问来源于stack exchange,提问作者Don40
相关产品推荐
相关产品推荐

