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

如何用Nuxt中间件正确校验Firebase Auth?解决端侧校验不一致问题

问题原因:服务端与客户端的Firebase Auth差异

核心差异点

  • Firebase Auth的用户认证状态存储在客户端(浏览器Cookie/IndexedDB),服务端无法直接访问这些客户端存储,因此服务端的auth.currentUser始终为null。
  • onAuthStateChanged是客户端专属的监听事件,服务端不会执行这个监听器,所以终端(服务端日志)会打印onAuthChangedListener called: undefined,而浏览器控制台(客户端日志)能正确获取已登录用户的UID。
  • 路由中间件会在服务端渲染阶段先执行一次,此时currentUser.value还是服务端初始化的null,所以即便客户端已登录,服务端仍会触发重定向到/login页面。

正确实现认证中间件的方案

步骤1:修正useAuth组合式函数

区分服务端与客户端逻辑,避免服务端无效的用户状态初始化:

import { type User, onAuthStateChanged } from 'firebase/auth';

export default function () {
  const nuxtApp = useNuxtApp();
  const auth = nuxtApp.$auth;

  const currentUser = useState<User | null>('fbUser', () => {
    // 服务端直接返回null,无法获取客户端认证状态
    if (process.server) return null;
    // 客户端初始化时读取本地当前用户
    return auth.currentUser;
  });

  // 仅在客户端挂载认证状态监听
  if (process.client) {
    onAuthStateChanged(auth, user => {
      console.log("onAuthStateChanged called:", user?.uid);
      currentUser.value = user;
    });
  }

  return {
    currentUser
  };
}

步骤2:修改路由中间件,处理异步认证状态

中间件需要等待客户端的认证状态就绪,同时跳过服务端的无效校验:

export default defineNuxtRouteMiddleware(async (to, from) => {
  const { currentUser } = useAuth();

  // 服务端直接放行,无法校验客户端认证状态,交由客户端后续处理
  if (process.server) return;

  // 客户端等待认证状态初始化完成
  if (!currentUser.value) {
    await new Promise(resolve => {
      const unsubscribe = onAuthStateChanged(useNuxtApp().$auth, user => {
        currentUser.value = user;
        unsubscribe(); // 监听一次后取消订阅
        resolve(user);
      });
    });
  }

  // 最终校验用户状态,未登录则重定向
  if (!currentUser.value) {
    return navigateTo('/login');
  }
});

补充说明

  • 如果需要在服务端也能获取用户状态,需要额外实现自定义会话同步:比如客户端登录后将Firebase的ID Token发送到服务端,服务端验证后存储会话,后续请求通过Cookie传递会话信息。但这会增加复杂度,大多数场景下客户端校验已足够。
  • 确保Firebase Auth在Nuxt中的初始化逻辑正确,避免服务端重复初始化auth实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:15:29