Electron中Firebase Authentication持久化异常:新窗口currentUser为null
Electron中Firebase Auth跨BrowserWindow丢失用户状态的解决方案
问题根源
Electron的每个BrowserWindow默认对应独立的渲染进程,进程间的localStorage完全隔离。Firebase Auth默认用browserLocalPersistence存储用户登录凭证,新窗口的渲染进程无法访问原窗口的localStorage内容,因此重新初始化Auth后auth.currentUser会返回null。
解决方法
方法1:主进程统一管理Auth状态
利用Electron主进程的单例特性,将Firebase Auth的初始化和状态管理放在主进程中,所有渲染进程通过IPC与主进程交互获取用户状态。
主进程代码示例
const { initializeApp } = require('firebase/app'); const { getAuth, signInWithEmailAndPassword, onAuthStateChanged } = require('firebase/auth'); const { ipcMain, BrowserWindow } = require('electron'); // 初始化Firebase const firebaseConfig = { /* 你的Firebase配置 */ }; const app = initializeApp(firebaseConfig); const auth = getAuth(app); // 处理渲染进程的登录请求 ipcMain.handle('auth-sign-in', async (_, email, password) => { try { const userCredential = await signInWithEmailAndPassword(auth, email, password); return { user: userCredential.user.toJSON() }; } catch (err) { return { error: err.message }; } }); // 主动向所有窗口同步用户状态变化 onAuthStateChanged(auth, (user) => { const userData = user ? user.toJSON() : null; BrowserWindow.getAllWindows().forEach(win => { win.webContents.send('auth-state-updated', userData); }); }); // 处理渲染进程的当前用户查询请求 ipcMain.handle('auth-get-current-user', () => { return auth.currentUser ? auth.currentUser.toJSON() : null; });
登录窗口(渲染进程)代码示例
const { ipcRenderer } = require('electron'); async function handleLogin(email, password) { const result = await ipcRenderer.invoke('auth-sign-in', email, password); if (result.user) { // 登录成功后打开新窗口 window.open('/path-to-new-window'); } else { console.error('登录失败:', result.error); } }
新窗口(渲染进程)代码示例
const { ipcRenderer } = require('electron'); // 监听主进程推送的状态变化 ipcRenderer.on('auth-state-updated', (_, user) => { console.log('当前用户:', user); // 这里更新UI或业务逻辑 }); // 初始化时主动拉取一次用户状态 async function initAuth() { const user = await ipcRenderer.invoke('auth-get-current-user'); console.log('初始化用户状态:', user); } initAuth();
方法2:让窗口共享同一个Session
通过设置BrowserWindow的webPreferences.partition参数,让多个窗口共享同一个会话(包含localStorage、Cookie等),这样Firebase Auth的持久化凭证可以在窗口间共享。
代码示例
// 创建登录窗口时指定持久化的partition const loginWindow = new BrowserWindow({ webPreferences: { partition: 'persist:firebase-auth-session', // persist:前缀表示会话会持久化到磁盘 contextIsolation: true, nodeIntegration: false } }); // 创建新窗口时使用同一个partition const newWindow = new BrowserWindow({ webPreferences: { partition: 'persist:firebase-auth-session', contextIsolation: true, nodeIntegration: false } });
使用这种方式后,新窗口初始化Firebase Auth时会自动读取共享的localStorage中的凭证,auth.currentUser会正常返回登录用户。
你之前代码的问题点
setPersistence的调用时机错误,它应该在登录操作前设置,而不是在onAuthStateChanged回调中。正确的写法是:
const auth = getAuth(app); // 先设置持久化 await setPersistence(auth, browserLocalPersistence); // 再执行登录 const userCredential = await signInWithEmailAndPassword(auth, email, password);
即便设置了正确的持久化,若窗口间Session隔离,依然无法共享状态,所以需要结合上面的两种方法解决。
内容的提问来源于stack exchange,提问作者Mohamed Hussein
相关产品推荐
相关产品推荐

