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

Node.js服务端携带AppCheck令牌请求Cloud Firestore实现方案

Node.js中间层透传App Check令牌访问Firestore的可行方案

核心前提:放弃使用Admin SDK直接执行用户态Firestore CRUD操作——Admin SDK默认持有项目全量读写权限,会完全跳过App Check校验与安全规则,无法实现基于客户端身份的权限控制。

完整实现流程如下:

1. 前置校验客户端上传的凭证

中间层拿到Android客户端请求携带的App Check令牌、Firebase Auth ID令牌(如果你的安全规则依赖用户身份)后,首先用Admin SDK做合法性校验,拦截伪造、过期的无效请求,这一步仅用Admin SDK做令牌校验,不涉及Firestore读写。

const admin = require('firebase-admin');
// 仅将Admin SDK用于凭证校验,不用于Firestore操作
admin.initializeApp({
  credential: admin.credential.applicationDefault()
});

// 校验App Check令牌有效性
async function validateAppCheckToken(clientToken) {
  try {
    const claims = await admin.appCheck().verifyToken(clientToken);
    return { valid: true, claims };
  } catch (err) {
    return { valid: false, err: err.message };
  }
}

// 校验Auth ID令牌有效性(按需使用)
async function validateAuthToken(clientIdToken) {
  try {
    const decoded = await admin.auth().verifyIdToken(clientIdToken);
    return { valid: true, uid: decoded.uid };
  } catch (err) {
    return { valid: false, err: err.message };
  }
}

2. 初始化Firebase客户端SDK(非Admin SDK)

只有Firebase客户端SDK会默认走App Check校验、安全规则校验流程,Node.js服务端可以直接集成官方JS客户端SDK,注意初始化时使用项目公开的Web端配置,不要使用服务账号凭证。

const { initializeApp } = require('firebase/app');
const { getFirestore } = require('firebase/firestore');
const { initializeAppCheck, CustomProvider } = require('firebase/app-check');
const { getAuth, signInWithCustomToken } = require('firebase/auth');

// 替换为你项目的Web端Firebase公开配置
const firebaseClientConfig = {
  apiKey: "项目Web API Key",
  authDomain: "项目Auth域名",
  projectId: "项目ID",
  storageBucket: "项目存储桶地址",
  messagingSenderId: "项目消息发送者ID",
  appId: "项目Web端AppID"
};

// 每个请求单独初始化客户端实例,避免身份、令牌串用
async function initRequestScopedClient(validAppCheckToken, uid) {
  const app = initializeApp(firebaseClientConfig);
  const db = getFirestore(app);
  const auth = getAuth(app);

  // 注入校验通过的客户端App Check令牌
  const appCheckProvider = new CustomProvider({
    getToken: () => ({
      token: validAppCheckToken,
      expireTimeMillis: Date.now() + 3600 * 1000 // 与令牌实际过期时间对齐即可
    })
  });
  initializeAppCheck(app, {
    provider: appCheckProvider,
    isTokenAutoRefreshEnabled: false
  });

  // 如果需要用户身份,生成短期自定义令牌登录
  if (uid) {
    const customToken = await admin.auth().createCustomToken(uid);
    await signInWithCustomToken(auth, customToken);
  }

  return { db, auth, app };
}

3. 单请求处理流程

每一个来自Android客户端的请求,按以下流程处理即可保证Firestore请求正常通过校验:

  • 从请求头提取客户端上传的App Check令牌、Auth ID令牌
  • 校验App Check令牌有效性,校验失败直接返回403拒绝
  • 按需校验Auth ID令牌有效性,校验失败直接返回403拒绝
  • 基于校验通过的凭证初始化当前请求专属的Firebase客户端实例,拿到db对象
  • 执行中间层需要的额外业务逻辑,通过拿到的db对象执行Firestore CRUD操作
  • 操作完成后销毁当前请求的客户端实例,避免内存泄漏

关键注意事项

  • 禁止全局复用Firebase客户端实例处理不同用户的请求,必须按请求维度初始化,避免令牌、身份串用导致越权
  • 所有客户端上传的令牌必须先经过Admin SDK校验,禁止直接透传未校验的令牌,防止伪造请求绕过校验
  • 生成的自定义令牌、缓存的App Check令牌必须设置最短有效期,降低凭证泄露风险
  • 该方案下Firestore请求的校验逻辑和Android客户端直连完全一致,不需要修改现有安全规则,规则中request.app、request.auth字段均可正常读取
  • 不要在客户端SDK中配置服务账号凭证,Web端Firebase配置本身属于公开信息,不存在安全风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:45:32