PAYATHON 2026

Firebase 支持哪些 payment gateways?

支付阿杰

结论

Firebase 不是支付网关,不能直接处理银行卡或 PayPal 等付款。它提供的主要是身份认证、数据库、云函数和托管等后端能力。

开发时,可以将 Firebase 与第三方支付服务配合使用,例如:

  • Stripe
  • PayPal
  • Adyen
  • Braintree
  • Square
  • 支付宝、微信支付等提供服务端 API 的支付平台
  • Apple App Store 和 Google Play 的应用内购买系统

Stripe 与 Firebase 的集成资料和现成方案比较多。接入其他支付网关时,通常需要使用 Cloud Functions 或独立后端。哪些平台可用,还要看商户注册地区、用户所在地、结算币种和业务类型。

Firebase 在支付流程中的作用

Firebase 通常负责支付流程中的后端辅助工作,不直接处理资金。一个常见流程是:

  1. Firebase Authentication 识别当前用户。
  2. 客户端向 Cloud Functions 请求创建订单。
  3. Cloud Functions 调用支付网关的服务端 API。
  4. 支付网关返回支付页面、支付令牌或客户端密钥。
  5. 用户在支付网关提供的安全界面中付款。
  6. 支付网关通过 Webhook 将支付结果通知服务器。
  7. Cloud Functions 验证通知,再把订单状态写入 Cloud Firestore。
  8. Firebase Security Rules 限制用户只能读取自己的订单。

这样可以避免将支付平台密钥放在客户端,也能防止客户端擅自修改订单金额或伪造支付结果。

以 Stripe 为例的基本接入方式

下面的示例展示了如何通过 Cloud Functions 创建 Stripe Checkout Session。实际接入时,需要按照当前 Firebase Functions SDK 和 Stripe SDK 的官方文档调整初始化方式及部署配置。

const { onCall, HttpsError } = require("firebase-functions/v2/https");
const { defineSecret } = require("firebase-functions/params");
const Stripe = require("stripe");

const stripeSecretKey = defineSecret("STRIPE_SECRET_KEY");

exports.createCheckoutSession = onCall(
  { secrets: [stripeSecretKey] },
  async (request) => {
    if (!request.auth) {
      throw new HttpsError("unauthenticated", "User must be signed in.");
    }

    const stripe = new Stripe(stripeSecretKey.value());

    // 商品和金额应从可信数据库读取,不能直接相信客户端提交的数据。
    const session = await stripe.checkout.sessions.create({
      mode: "payment",
      line_items: [
        {
          price: "price_xxxxxxxxxxxxx",
          quantity: 1,
        },
      ],
      success_url: "https://example.com/payment/success?session_id={CHECKOUT_SESSION_ID}",
      cancel_url: "https://example.com/payment/cancel",
      client_reference_id: request.auth.uid,
      metadata: {
        firebaseUid: request.auth.uid,
      },
    });

    return {
      sessionId: session.id,
      url: session.url,
    };
  }
);

客户端登录 Firebase 后,可以调用这个 Callable Function:

import { getFunctions, httpsCallable } from "firebase/functions";

const functions = getFunctions();
const createCheckoutSession = httpsCallable(
  functions,
  "createCheckoutSession"
);

const result = await createCheckoutSession();
window.location.href = result.data.url;

客户端不应传入最终支付金额。更稳妥的做法是只提交商品 ID,再由 Cloud Functions 从 Firestore 或其他可信数据源查询价格。

必须使用 Webhook 确认付款

用户进入成功页面,只能说明浏览器完成了跳转,不能证明款项已经支付。订单状态必须以通过签名验证的支付网关 Webhook 事件为准。

const { onRequest } = require("firebase-functions/v2/https");
const { defineSecret } = require("firebase-functions/params");
const admin = require("firebase-admin");
const Stripe = require("stripe");

admin.initializeApp();

const stripeSecretKey = defineSecret("STRIPE_SECRET_KEY");
const stripeWebhookSecret = defineSecret("STRIPE_WEBHOOK_SECRET");

exports.stripeWebhook = onRequest(
  {
    secrets: [stripeSecretKey, stripeWebhookSecret],
  },
  async (req, res) => {
    const stripe = new Stripe(stripeSecretKey.value());
    const signature = req.headers["stripe-signature"];

    let event;

    try {
      event = stripe.webhooks.constructEvent(
        req.rawBody,
        signature,
        stripeWebhookSecret.value()
      );
    } catch (error) {
      res.status(400).send(`Webhook Error: ${error.message}`);
      return;
    }

    if (event.type === "checkout.session.completed") {
      const session = event.data.object;
      const uid = session.metadata?.firebaseUid;

      if (uid) {
        await admin.firestore()
          .collection("payments")
          .doc(session.id)
          .set(
            {
              uid,
              status: "paid",
              paymentStatus: session.payment_status,
              updatedAt: admin.firestore.FieldValue.serverTimestamp(),
            },
            { merge: true }
          );
      }
    }

    res.status(200).send("ok");
  }
);

生产环境还要保存支付平台的事件 ID,并做好幂等处理。否则,同一个 Webhook 被重复投递时,可能造成重复发货或重复增加用户权益。

使用 Firebase Extension

Firebase 生态中可能有由 Firebase 或合作方维护的支付相关 Extension,例如用于连接 Stripe 客户、订阅和 Firestore 数据的扩展。

Extension 能减少订阅同步和 Webhook 处理等重复代码,但它并不意味着 Firebase 自己提供收款服务。安装前需要确认:

  • 扩展目前是否仍在维护
  • 支持一次性支付、订阅,还是两者都支持
  • 使用哪些 Firestore 集合和字段
  • 会部署哪些 Cloud Functions
  • 会产生哪些 Firebase 和支付平台费用
  • 是否符合所在地区及业务类型的要求

扩展的名称、配置项和支持范围都可能变化,应以安装时显示的官方说明为准。

PayPal、支付宝和微信支付如何接入

这些平台的接入流程与 Stripe 大致相同:

  1. 客户端向 Cloud Functions 提交商品或订单标识。
  2. Cloud Functions 从可信数据源计算价格。
  3. Cloud Functions 使用服务端凭据调用支付平台 API。
  4. 客户端完成授权或跳转支付。
  5. 支付平台向 Cloud Functions 的 HTTPS 地址发送异步通知。
  6. 服务端验证签名,并主动查询订单状态。
  7. 确认支付成功后更新 Firestore。

只要支付平台提供服务端 API、签名验证和异步通知机制,原则上就可以与 Firebase 配合使用。有些平台会要求固定出口 IP、特定运行环境、证书文件或区域部署。遇到这些限制时,可能需要改用 Cloud Run 或独立服务器,不能只依赖 Cloud Functions。

移动应用需要注意商店支付规则

如果应用销售数字内容、会员功能、虚拟物品或应用内服务,iOS 和 Android 可能要求使用各自的应用内购买系统:

  • iOS:StoreKit / In-App Purchase
  • Android:Google Play Billing

即使技术上能够接入 Stripe 或其他支付网关,也不能因此直接绕过应用商店的支付要求。实体商品、线下服务等场景可能适用不同规则。相关要求会随地区、应用类别和商店政策变化,上线前应核对 Apple App Store 与 Google Play 的最新规定。

Firebase 可以保存购买状态、处理服务端通知并授予用户权益,但交易本身仍由 Apple 或 Google 的支付系统完成。

安全与成本注意事项

  • 不要将支付网关的 Secret Key、私钥或 Webhook Secret 写入前端代码。
  • 不要信任客户端提交的金额、折扣、币种或”支付成功”状态。
  • Webhook 必须验证签名,并根据事件 ID 做幂等处理。
  • 发货或开通会员前,应检查订单金额、币种、商品和支付状态。
  • Firestore Security Rules 不能代替服务端支付验证。
  • 支付数据应尽量通过 Admin SDK 写入,客户端只保留必要的读取权限。
  • 不要在 Firestore 中保存完整银行卡号、CVV 等敏感卡片信息。
  • 退款、拒付、订阅续费失败和订阅取消也要通过 Webhook 同步。
  • 除支付网关手续费外,还要计算 Cloud Functions、Cloud Run、Firestore、网络流量和日志产生的费用。
  • 税费、发票、身份验证和支付合规要求取决于业务所在地及支付服务商的规则。

选择 Firebase 不会将应用限制在某一个 payment gateway 上。准确地说,Firebase 不负责收款,但可以作为应用后端,与提供服务端 API 的支付平台集成。选型时,需要比较目标地区、支付方式、应用商店规则、订阅需求、合规要求和总体成本。

备注:内容仅供参考。