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

SvelteKit +page.ts load中FirebaseAuth用户始终为null的解决方法咨询

解决方案

一、客户端Load函数修复(保持SSR=false)

问题核心是Firebase Auth的会话恢复是异步过程,load函数执行时Auth还未完成初始化,导致currentUser为null。可以通过等待Auth状态变化确保拿到用户:

  1. 封装等待用户加载的工具函数:
import { type Auth, onAuthStateChanged } from "firebase/auth";

function waitForUser(auth: Auth): Promise<User | null> {
  return new Promise((resolve) => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      unsubscribe();
      resolve(user);
    });
  });
}
  1. 修改+page.ts的load函数:
import { getAuth } from "firebase/auth";
import { error } from "@sveltejs/kit";
import type { PageLoad } from "./$types";

export const load = (async () => {
  const auth = getAuth();
  // 等待Auth完成会话恢复,拿到用户
  const user = await waitForUser(auth);
  
  if (!user) throw error(401, "Could not authenticate");
  
  const token = await user.getIDToken();
  const data = await api.requestData(token);
  
  return { data };
}) satisfies PageLoad;

export const ssr = false;

这个方案会让load函数等待用户状态加载完成后再请求数据,避免页面渲染后二次请求。

二、服务端认证方案(更推荐)

SvelteKit完全支持服务端认证,这种方式更安全,且无需依赖客户端Firebase初始化:

步骤1:客户端登录后存储ID Token到Cookie

登录成功后,将ID Token存入HttpOnly Cookie(防止XSS攻击):

import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";

async function handleGoogleLogin() {
  const auth = getAuth();
  const provider = new GoogleAuthProvider();
  const result = await signInWithPopup(auth, provider);
  
  const token = await result.user.getIDToken();
  // 设置Cookie,有效期与ID Token一致(默认1小时)
  document.cookie = `id_token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600; Path=/`;
  
  // 登录成功后跳转或刷新页面
  window.location.href = "/";
}

步骤2:服务端验证Token并注入用户信息

在hooks.server.ts中验证Cookie里的ID Token,将用户信息存入locals:

import { adminAuth } from "$lib/server/firebase-admin"; // 已初始化的Firebase Admin实例
import type { Handle } from "@sveltejs/kit";

export const handle: Handle = async ({ event, resolve }) => {
  const token = event.cookies.get("id_token");
  
  if (token) {
    try {
      // 验证ID Token合法性
      const decodedToken = await adminAuth.verifyIdToken(token);
      event.locals.user = {
        uid: decodedToken.uid,
        email: decodedToken.email
      };
    } catch (err) {
      // 验证失败,清除无效Cookie
      event.cookies.delete("id_token");
    }
  }
  
  return resolve(event);
};

步骤3:服务端Load函数获取数据

改用+page.server.ts的服务端Load函数,直接通过locals获取用户信息并请求数据:

import { error } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";
import { api } from "$lib/server/api"; // 服务端API请求工具

export const load: PageServerLoad = async ({ locals }) => {
  if (!locals.user) throw error(401, "Could not authenticate");
  
  // 直接使用验证后的用户信息请求数据(无需再传Token到API,或根据API要求处理)
  const data = await api.requestData(locals.user.uid);
  
  return { data };
};

注意事项

  • Firebase Admin需提前初始化:使用服务账号密钥创建Admin实例,确保服务端能验证Token。
  • Token刷新:ID Token有效期为1小时,需在客户端监听onIdTokenChanged事件,自动更新Cookie。
  • Cookie安全性:生产环境务必开启Secure属性(仅HTTPS传输),避免Cookie被窃取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:30:57