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

如何通过Stripe PaymentIntent API复用自有存储的银行卡数据?

问题描述

我正在使用Angular、Stripe.js 3、Stripe Elements、Spring Boot以及Stripe PaymentIntent API开发支付功能。目前已通过Stripe Elements实现支持Strong Customer Authentication(SCA)的支付流程,可成功跳转至支付验证页面。但当前存在问题:每次支付都需要用户手动输入银行卡信息,而我的应用已独立于Stripe存储了用户的银行卡数据,希望实现卡片保存功能,无需用户重复输入。请问如何将自有表单中的银行卡数据传递给Stripe.js,以实现该需求?

相关代码

HTML代码

<!-- <form novalidate>
  <input type="text" name="cardNumber" id="" placeholder="Card Number">
  <input type="text" name="expiry-month" id="" placeholder="Expiry Month">
  <input type="text" name="expiry-year" id="" placeholder="Expiry Year">
  <input type="text" name="cardNumber" id="" placeholder="CVV">

</form> -->
<form id="payment-form">
  <div id="link-authentication-element">
    <!--Stripe.js injects the Link Authentication Element-->
  </div>
  <div id="payment-element" class="stripe-form-input">
    <!--Stripe.js injects the Payment Element-->
  </div>
  <!-- <button id="submit">
    <div class="spinner hidden" id="spinner"></div>
    <span id="button-text">Pay now</span>
  </button> -->
  <div id="payment-message" class="hidden"></div>
</form>

</div>

<button type="submit" class="fill" style="width: 100%;" (click)="testCreateCard()">Pay</button>
<div class="iframe-wrapper" #if> <iframe *ngIf="showIframe" frameborder="0" [src]="ifHtml | safe" height="600" width="400" #if></iframe></div>

TypeScript代码

export class AppComponent {
  title = 'stripePaymentIntents';
  clientSecret:string = ""
  elements:any;
  email?:string;
  paymentElement:any;

  showIframe:boolean = false;
  ifHtml:string = ""

  paymentIntent:string = ""
  @ViewChild('if') iframeWrapper!: ElementRef;

  constructor(private http: HttpClient, private sanitizer: DomSanitizer, private route: ActivatedRoute){}

  ngOnInit(): void {
    this.route.queryParams.subscribe(qp => {
      this.paymentIntent = qp['payment_intent']
      console.log("Payment Intent From SCA:   " + this.paymentIntent)
    })

    const appearance = {
      theme: 'stripe',
    };

    this.http.get("http://localhost:8080/api/payment/intent/clientSecret", {responseType:'text'}).subscribe(secret => {
      this.elements = stripe.elements({ appearance, clientSecret: secret });
      this.clientSecret = secret;
      const linkAuthenticationElement = this.elements.create("linkAuthentication");
      linkAuthenticationElement.mount("#link-authentication-element");

      linkAuthenticationElement.on('change', (event:any) => {
          this.email = event.value.email;
      });

      const paymentElementOptions = {
          layout: "tabs",
      };

      const cardElementStyle = {
        classes: 'stripe-'
      }

      this.paymentElement = this.elements.create("card", paymentElementOptions);
      this.paymentElement.mount("#payment-element");
    })
  }

  testCreateCard(){
      console.log(this.clientSecret);
      console.log(this.elements);
      const here = this;

      stripe.confirmCardPayment(this.clientSecret, {
          payment_method: {
            card: this.paymentElement,
            billing_details: {
              name: 'Barack Obama',
            },
          },
            return_url: 'http://localhost:4200/'

        }, {handleActions: false})
        .then(function(result:any) {
          if(result.paymentIntent.next_action.redirect_to_url.url !== null){
            window.location = result.paymentIntent.next_action.redirect_to_url.url
          }

          if (result.error) {
            console.log(result);
          } else {
            here.showIframe = true
            console.log('iframe show; ' + here.showIframe);
            console.log("SUCCESS: ")
            console.log(result);
          }
        });
  }
}
解决方案

首先必须明确:Stripe不允许直接传递明文银行卡数据到Stripe.js——这会违反PCI合规要求,直接处理卡信息会让你的应用承担最高级别的PCI合规责任,风险极高。正确的做法是利用Stripe的Tokenization或Setup API安全处理已存储的卡信息,或者使用Stripe的Customer对象存储卡信息(推荐方案)。

方案1:使用Stripe Customer存储卡信息(推荐)

这是最安全且合规的方式,步骤如下:

  1. 后端创建Stripe Customer:用户首次添加卡片时,通过Stripe Elements收集卡信息,后端调用Stripe API创建PaymentMethod,再关联到Stripe Customer对象。
  2. 存储Stripe Customer ID:将Stripe返回的customer_id与你的系统用户关联存储,而非存储明文卡信息。
  3. 后续支付时复用PaymentMethod:
    • 后端创建PaymentIntent时,指定customer参数为存储的Stripe Customer ID,同时可指定payment_method为该用户已保存的PaymentMethod ID。
    • 前端无需再收集卡信息,Stripe Elements的Payment Element会自动加载用户已保存的卡片供选择。

代码调整示例

后端(Spring Boot)创建关联PaymentMethod的Customer

// 伪代码,需引入Stripe Java SDK
CustomerCreateParams customerParams = CustomerCreateParams.builder()
    .setEmail(userEmail)
    .build();
Customer customer = Customer.create(customerParams);

// 将PaymentMethod关联到Customer
PaymentMethodAttachParams attachParams = PaymentMethodAttachParams.builder()
    .setCustomer(customer.getId())
    .build();
PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodId);
paymentMethod.attach(attachParams);

// 将customer.getId()存储到你的用户表

前端(Angular)加载已保存卡片

初始化Elements时传入customer参数:

this.elements = stripe.elements({ 
  appearance, 
  clientSecret: secret,
  customer: 你的系统存储的stripeCustomerId // 添加该行
});
// 创建Payment Element时会自动加载用户已保存的卡片
this.paymentElement = this.elements.create("payment", paymentElementOptions);

方案2:若必须使用自有存储的卡信息(不推荐,需严格PCI合规)

如果因特殊原因必须自行存储卡信息,需使用Stripe的Token API将明文卡信息转换为Stripe Token,再用于支付:

  1. 前端收集卡信息:使用自有表单(需满足PCI SAQ D合规要求,包括HTTPS、数据加密等)。
  2. 调用Stripe.createToken创建卡Token:
// 从自有表单获取卡信息
const cardData = {
  number: 表单获取的卡号,
  exp_month: 表单获取的到期月,
  exp_year: 表单获取的到期年,
  cvc: 表单获取的CVV
};

stripe.createToken('card', cardData).then((result) => {
  if (result.error) {
    // 处理错误
  } else {
    // 将token.id传给后端,用于创建PaymentMethod或直接支付
    this.http.post("/api/payment/create-payment-intent", {
      token: result.token.id,
      amount: 1000
    }).subscribe(secret => {
      // 后续调用confirmCardPayment
    });
  }
});
  1. 后端使用Token创建PaymentIntent:接收前端传来的Token,创建PaymentIntent时指定payment_method_data[type] = card和payment_method_data[card][token] = 前端传入的token。

注意:这种方式要求你的应用满足PCI SAQ D合规,成本和风险极高,强烈建议使用方案1。

关键注意事项

  • 永远不要在前端或后端存储明文银行卡信息,包括卡号、CVV、有效期。
  • Stripe Elements是Stripe提供的合规收集卡信息的方式,尽量使用它规避PCI合规风险。
  • 复用已保存的PaymentMethod时,Stripe会自动处理SCA验证流程,无需额外开发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 01:07:08