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

Next.js 14服务端组件结合Firebase Auth调用Firestore权限被拒

问题分析与解决方案

核心问题:你在Next.js 14 SSR中使用Firebase Session Cookie认证,但客户端Firestore SDK发起请求时并未携带有效认证信息,导致Firestore安全规则触发权限拒绝。客户端auth.currentUser为undefined,是因为Firebase客户端Auth不会自动读取Session Cookie,必须手动完成认证流程。

解决方案1:服务端使用Firebase Admin SDK操作Firestore

Admin SDK在服务端运行,拥有最高权限,无需通过客户端安全规则校验,适合SSR场景下的服务端数据获取。

步骤:

  1. 初始化Firebase Admin App(确保只初始化一次)
  2. 验证Session Cookie获取用户UID
  3. 使用Admin SDK查询Firestore
import { cookies } from 'next/headers';
import { getAuth } from 'firebase-admin/auth';
import { getFirestore } from 'firebase-admin/firestore';
import { initializeApp, getApps } from 'firebase-admin/app';

// 初始化Admin App(避免重复初始化)
if (!getApps().length) {
  initializeApp({
    // 填入你的Firebase Admin配置(从控制台获取)
  });
}

// 验证Session Cookie的工具函数
async function getAuthenticatedUid() {
  const sessionCookie = cookies().get('session')?.value;
  if (!sessionCookie) return null;

  try {
    // 验证Cookie有效性,开启checkRevoked确保Cookie未被撤销
    const decodedClaims = await getAuth().verifySessionCookie(sessionCookie, true);
    return decodedClaims.uid;
  } catch (err) {
    // Cookie无效/过期,可在此处处理跳转登录等逻辑
    return null;
  }
}

const AdminPage: React.FC = async () => {
  const fetchCount = async () => {
    const uid = await getAuthenticatedUid();
    if (!uid) throw new Error('用户未登录');

    // 使用Admin SDK的Firestore实例查询
    const db = getFirestore();
    const coll = db.collection('test_results');
    const snapshot = await coll.count().get();
    return snapshot.data().count;
  };

  const count = await fetchCount();

  return (
    <div>
      <p>COUNT : {count}</p>
    </div>
  );
};

export const dynamic = 'force-dynamic';
export default AdminPage;

解决方案2:为客户端Firestore SDK注入认证凭证

如果需要保留客户端Firestore SDK的使用(比如后续客户端交互需要),可在服务端验证Session Cookie后,通过自定义Token登录客户端Auth实例,让Firestore请求携带认证信息。

import { cookies } from 'next/headers';
import { getAuth as getAdminAuth } from 'firebase-admin/auth';
import { initializeApp, getApps } from 'firebase-admin/app';
import { getAuth, signInWithCustomToken } from 'firebase/auth';
import { getFirestore, collection, getCountFromServer } from 'firebase/firestore';

// 初始化Admin App
if (!getApps().length) {
  initializeApp({ /* Admin配置 */ });
}

// 客户端Firebase配置
const clientFirebaseConfig = { /* 你的客户端Firebase配置 */ };
const clientApp = getApps().find(app => app.name === '[DEFAULT]') || initializeApp(clientFirebaseConfig);

const AdminPage: React.FC = async () => {
  const fetchCount = async () => {
    const sessionCookie = cookies().get('session')?.value;
    if (!sessionCookie) throw new Error('用户未登录');

    // 验证Session Cookie
    const decodedClaims = await getAdminAuth().verifySessionCookie(sessionCookie, true);
    // 生成自定义Token
    const customToken = await getAdminAuth().createCustomToken(decodedClaims.uid);

    // 在服务端登录客户端Auth实例
    const clientAuth = getAuth(clientApp);
    await signInWithCustomToken(clientAuth, customToken);

    // 此时Firestore请求会携带认证信息
    const db = getFirestore(clientApp);
    const coll = collection(db, 'test_results');
    const snapshot = await getCountFromServer(coll);
    return snapshot.data().count;
  };

  const count = await fetchCount();

  return (
    <div>
      <p>COUNT : {count}</p>
    </div>
  );
};

export const dynamic = 'force-dynamic';
export default AdminPage;

关键说明

  • Session Cookie是给服务端验证用的,客户端Firebase Auth不会自动识别它,必须通过signInWithCustomToken等方法手动初始化登录状态,才会生成currentUser。
  • 使用Admin SDK时,无需受Firestore安全规则限制(Admin拥有完全权限),如果需要严格遵循规则,建议使用解决方案2。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 18:08:12