Node.js集成Stripe时避免用户重复添加银行卡的实现方案咨询
重复银行卡绑定校验及处理的规范实现方案
你提到的fingerprint校验其实是Stripe官方推荐的标准方案,你觉得不合理大概率是对这个字段的生成规则不够了解:Stripe返回的卡片fingerprint是基于卡号、有效期等核心卡信息生成的全局唯一值,同一张卡不管生成多少次token,对应的fingerprint完全一致,且不会和其他卡重复,也符合PCI DSS合规要求,不需要你侧处理任何敏感卡信息,是目前最规范的实现方案。
具体实现逻辑如下:
- 加卡前先查询当前用户名下所有已绑定的卡片,拿到所有卡的fingerprint集合
- 调用Stripe的token查询接口,获取新提交token对应的卡片fingerprint和卡组织信息
- 匹配到重复卡片时,按需选择直接返回已有卡片并提示绑定,或者更新已有卡片信息后返回
- 未匹配到重复卡片时,先校验对应卡组织的绑定数量上限,校验通过后再执行新增操作
代码修改示例
首先给Stripe客户端服务新增3个辅助方法:
// 获取token对应的卡片基础信息 public async getCardFromToken(token: string): Promise<Stripe.Card> { const tokenInfo = await this.stripeClient.tokens.retrieve(token); return tokenInfo.card as Stripe.Card; } // 拉取用户所有已绑定的银行卡 public async listAllCards(customerId: string): Promise<Stripe.Card[]> { const sources = await this.stripeClient.customers.listSources(customerId, { object: 'card', limit: 20 // 覆盖你允许的最大绑定数量即可 }); return sources.data as Stripe.Card[]; } // 更新已有卡片的信息 public async updateCard(customerId: string, cardId: string, params: Stripe.CardUpdateParams): Promise<Stripe.Card> { return await this.stripeClient.customers.updateSource(customerId, cardId, params) as Stripe.Card; }
然后修改原有的addNewCard逻辑:
public async addNewCard(customerId: string, newCardRequest: NewCardRequest): Promise<Card> { const stripeCustomerId = await this.getStripeCustomerId(customerId); // 提前获取新卡的标识和卡组织信息 const newCardInfo = await this.stripeApi.getCardFromToken(newCardRequest.token); const newCardFingerprint = newCardInfo.fingerprint; const newCardBrand = newCardInfo.brand; // 新用户无存量卡,直接创建 if (!stripeCustomerId) { const stripeCustomer = await this.createStripeCustomer(customerId, newCardRequest.token, newCardRequest.nameOnCard); const card = await this.stripeApi.getCard(stripeCustomer.id, stripeCustomer.defaultPaymentMethodId); return Card.fromStripeCard(card); } // 老用户先校验重复卡 const existCards = await this.stripeApi.listAllCards(stripeCustomerId); const duplicateCard = existCards.find(card => card.fingerprint === newCardFingerprint); if (duplicateCard) { // 可选分支1:直接返回已有卡片,可通过自定义返回字段或者抛出业务异常告知用户卡已绑定 // return Card.fromStripeCard(duplicateCard); // 可选分支2:更新已有卡片信息后返回 const updatedCard = await this.stripeApi.updateCard(stripeCustomerId, duplicateCard.id, { name: newCardRequest.nameOnCard }); return Card.fromStripeCard(updatedCard); } // 校验卡组织绑定数量上限 const sameBrandCount = existCards.filter(card => card.brand === newCardBrand).length; if ((newCardBrand === 'American Express' && sameBrandCount >= 4) || (newCardBrand === 'Visa' && sameBrandCount >= 10)) { throw new Error(`当前${newCardBrand}卡绑定数量已达上限`); } // 所有校验通过,执行新增 const card = await this.stripeApi.addCard(stripeCustomerId, newCardRequest.token, { nameOnCard: newCardRequest.nameOnCard}); return Card.fromStripeCard(card); }
注意事项
不要在调用完addCard接口后再做重复校验,否则会在Stripe侧生成冗余的卡片记录,需要额外调用删除接口清理,增加不必要的请求开销。
内容的提问来源于stack exchange,提问作者Ehsan Nissar
相关产品推荐
相关产品推荐

