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

如何基于Firebase Stripe扩展实现多订阅功能并同步activePlans数组?

解决方案:两种方式实现多订阅的activePlans同步

好问题!Firebase Stripe扩展默认确实是为单订阅场景设计的,但完全可以通过自定义调整来实现你需要的多订阅activePlans数组功能,下面分两种常用方案给你拆解:

方案一:修改Auth自定义声明为数组(适合前端快速权限验证)

扩展默认的stripeRole字段只支持单个plan ID,但你可以修改扩展的云函数逻辑,把它改成维护一个数组:

  1. 找到扩展中负责更新用户自定义声明的云函数(通常是处理Stripe订阅webhook的函数)
  2. 替换原来的单值赋值逻辑,改为先读取用户现有声明,再更新数组:
const admin = require('firebase-admin');

// 处理订阅状态变更的核心逻辑片段
async function updateUserClaims(uid, subscription) {
  const planId = subscription.plan.id;
  const user = await admin.auth().getUser(uid);
  const currentClaims = user.customClaims || {};
  
  // 初始化或获取现有activePlans数组
  let activePlans = currentClaims.activePlans || [];

  // 根据订阅状态更新数组
  if (['active', 'trialing'].includes(subscription.status)) {
    // 订阅有效且未在数组中,添加进去
    if (!activePlans.includes(planId)) {
      activePlans.push(planId);
    }
  } else {
    // 订阅过期/取消,从数组中移除
    activePlans = activePlans.filter(id => id !== planId);
  }

  // 更新自定义声明
  await admin.auth().setCustomUserClaims(uid, {
    ...currentClaims,
    activePlans: activePlans.length > 0 ? activePlans : undefined // 空数组时可移除字段
  });
}

⚠️ 注意:Auth自定义声明有10KB大小限制,如果用户订阅的计划数量较多,建议用下面的Firestore方案。另外,直接修改扩展代码后,后续官方扩展更新会覆盖你的修改,最好把这段逻辑复制成独立的云函数,脱离原扩展维护。

方案二:在Firestore用户文档中维护activePlans数组(更灵活)

既然扩展已经把订阅数据同步到users/{uid}/subscriptions子集合,你可以写一个独立的云函数,监听子集合的变化,自动聚合出有效的plan ID数组并更新到用户主文档:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

exports.syncActivePlansToUserDoc = functions.firestore
  .document('users/{uid}/subscriptions/{subscriptionId}')
  .onWrite(async (change, context) => {
    const uid = context.params.uid;
    const userDocRef = admin.firestore().collection('users').doc(uid);

    // 查询所有处于有效状态的订阅
    const activeSubsSnapshot = await userDocRef.collection('subscriptions')
      .where('status', 'in', ['active', 'trialing'])
      .get();

    // 提取plan ID并去重(避免同一计划多次订阅)
    const activePlans = [...new Set(
      activeSubsSnapshot.docs.map(doc => doc.data().plan.id)
    )];

    // 更新用户文档的activePlans字段
    return userDocRef.update({ activePlans });
  });

这样前端直接读取users/{uid}文档的activePlans字段即可,不用遍历子集合,而且没有大小限制,还能配合Firestore规则做更精细的权限控制。

总结

  • 如果需要在前端或Firebase规则中快速验证订阅权限,方案一更合适;
  • 如果用户可能订阅多个计划,或者需要关联更多订阅元数据,方案二更灵活可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 16:47:32