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

Firebase Auth currentUser始终为null,SvelteKit路由刷新后被踢

解决方案:SvelteKit路由保护中Firebase认证状态同步问题

核心问题是SvelteKit的load函数默认在服务端执行时,Firebase的onAuthStateChanged还未完成客户端的认证状态同步,导致直接读取authUser store得到null,触发不必要的登录跳转。以下是针对性修复方案:

1. 异步等待认证状态初始化(推荐)

在authStore中封装异步函数,确保load函数能等到Firebase完成认证状态同步后再判断:

修改src/lib/authStore.ts:

import { writable } from 'svelte/store';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from './firebase'; 

type AuthUser = {
    uid: string;
    email: string | null;
} | null;

export const authUser = writable<AuthUser>(null);

// 新增:异步获取认证用户,等待首次状态同步
export const getAuthUser = async (): Promise<AuthUser> => {
    // 先检查store已有值
    const currentUser = authUser.subscribe(val => val)();
    if (currentUser !== null) return currentUser;

    // 等待Firebase返回认证状态
    return new Promise(resolve => {
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            const mappedUser: AuthUser = user ? { uid: user.uid, email: user.email } : null;
            authUser.set(mappedUser);
            resolve(mappedUser);
            unsubscribe(); // 获取结果后取消监听
        });
    });
};

更新受保护路由的src/routes/protected/+page.ts:

import { redirect } from "@sveltejs/kit";
import { getAuthUser } from '$lib/authStore';

export const load = async () => {
    const user = await getAuthUser();
    if (!user) {
        throw redirect(302, '/login'); 
    }
    return { user };
};

2. 禁用该路由的SSR(快速临时方案)

如果受保护页面不需要服务端渲染,可以直接关闭SSR,确保代码在客户端执行时Firebase已完成状态同步:

// src/routes/protected/+page.ts
export const ssr = false;

export const load = async () => {
    const { getAuthUser } = await import('$lib/authStore');
    const user = await getAuthUser();
    if (!user) throw redirect(302, '/login');
    return { user };
};

3. 清理登录页冗余代码

登录页中重复的onAuthStateChanged监听是多余的,authStore已全局处理状态同步,直接跳转即可:

<!-- src/routes/login/+page.svelte -->
<script lang="ts">
    import { goto } from '$app/navigation';
    import { signInWithEmailAndPassword} from 'firebase/auth';
    import { auth } from "$lib/firebase";

    let email: string = '';
    let password: string = '';

    const login = () => {
        signInWithEmailAndPassword(auth, email, password)
            .then(() => goto('/protected'))
            .catch((error) => console.log(error.code, error.message));
    };
</script>

4. 显式配置Firebase持久化

确保Firebase认证状态在页面刷新后保留,在src/lib/firebase.ts中添加持久化配置:

import { initializeApp, getApps} from "firebase/app";
import { getAuth, setPersistence, browserLocalPersistence } from "firebase/auth";

const firebaseConfig = {
    apiKey: "",
    authDomain: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: "",
    appId: "",
    measurementId: ""
};

const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
export const auth = getAuth(app);

// 强制设置本地持久化
setPersistence(auth, browserLocalPersistence)
    .catch(err => console.error('持久化配置失败:', err));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 12:45:57