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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 23:26:25