首页 > web前端 > js教程 > 正文

Stripe PaymentIntent API:安全地保存和复用银行卡信息

聖光之護
发布: 2025-07-15 23:02:33
原创
520人浏览过

stripe paymentintent api:安全地保存和复用银行卡信息

本教程详细阐述了在使用Stripe PaymentIntent API时,如何安全地保存客户银行卡信息以供未来支付。强调了PCI DSS合规性的重要性,并指导开发者利用Stripe的PaymentMethod和Customer对象,而非自行存储敏感卡数据,从而实现便捷且安全的重复支付体验。

1. 理解PCI DSS合规性与数据安全

在处理银行卡数据时,首要且最关键的原则是遵守支付卡行业数据安全标准(PCI DSS)。PCI DSS旨在保护持卡人数据,其要求非常严格。除非您的组织达到了PCI DSS一级服务提供商或SAQ D级别,否则绝不应在自己的服务器上存储原始银行卡号、有效期或CVV等敏感信息。自行存储这些数据不仅风险巨大,还可能导致严重的法律和财务后果。

Stripe作为PCI DSS一级服务提供商,提供了安全的方式来处理和存储银行卡信息。最佳实践是让Stripe来处理所有敏感数据,您只需存储Stripe返回的非敏感标识符(如PaymentMethod ID)。

2. Stripe的解决方案:PaymentMethod与Customer对象

Stripe提供了PaymentMethod和Customer对象来安全地管理客户的支付信息。

  • PaymentMethod:代表一种支付方式(如银行卡、银行账户等)。它包含了加密的支付信息,并由Stripe安全存储。您会获得一个pm_xxx格式的ID,用于后续操作。
  • Customer:代表您的客户。您可以将一个或多个PaymentMethod关联到特定的Customer对象。这样,当客户再次购买时,您只需使用其Customer ID和关联的PaymentMethod ID即可完成支付,无需再次输入卡信息。

3. 在PaymentIntent流程中保存银行卡信息

Stripe允许您在创建PaymentIntent时,同时收集并保存客户的支付方式,以供未来使用。这通过在创建PaymentIntent时设置setup_future_usage参数来实现。

3.1 后端实现:创建带有 setup_future_usage 的 PaymentIntent

当您的前端请求创建一个支付意图时,后端(例如Spring Boot)应在创建PaymentIntent时指定setup_future_usage参数。这告诉Stripe在支付成功后保存此支付方式。

// Spring Boot (Java) 示例 - 创建 PaymentIntent
import com.stripe.Stripe;
import com.stripe.model.PaymentIntent;
import com.stripe.param.PaymentIntentCreateParams;

public class PaymentService {

    public String createPaymentIntentWithSaveOption(long amount, String currency, String customerId) throws StripeException {
        Stripe.apiKey = "YOUR_STRIPE_SECRET_KEY"; // 替换为您的Stripe Secret Key

        PaymentIntentCreateParams.Builder paramsBuilder = PaymentIntentCreateParams.builder()
            .setAmount(amount) // 支付金额,单位为最小货币单位(如美分)
            .setCurrency(currency) // 货币类型,如 "usd", "eur"
            .addPaymentMethodType("card") // 允许的支付方式类型
            .setSetupFutureUsage(PaymentIntentCreateParams.SetupFutureUsage.OFF_SESSION); // 关键:设置为离线会话使用

        // 如果您有客户ID,可以将其关联到PaymentIntent
        if (customerId != null && !customerId.isEmpty()) {
            paramsBuilder.setCustomer(customerId);
        }

        PaymentIntent intent = PaymentIntent.create(paramsBuilder.build());
        return intent.getClientSecret(); // 返回 client secret 给前端
    }
}
登录后复制

setup_future_usage 参数的含义:

  • off_session:表示此支付方式将在客户不在场(离线)时被复用。
  • on_session:表示此支付方式将在客户在场(在线)时被复用。

通常,为了实现“保存卡片,下次无需输入”的功能,您会选择off_session。

3.2 前端实现:使用 Payment Element 确认 PaymentIntent

前端(例如Angular应用)使用Stripe.js和Payment Element来收集客户的银行卡信息,并确认PaymentIntent。前端无需关心setup_future_usage,因为它已在后端PaymentIntent创建时设置。

Waymark
Waymark

Waymark是一个视频制作工具,帮助企业快速轻松地制作高影响力的广告。

Waymark 79
查看详情 Waymark
// Angular Component (AppComponent)
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

// 确保在 index.html 中引入了 Stripe.js
declare var Stripe: any;

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'stripePaymentIntents';
  clientSecret: string = "";
  elements: any;
  email?: string;
  paymentElement: any; // 用于挂载 Payment Element

  // ... 其他属性和构造函数

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

  ngOnInit(): void {
    // 1. 从后端获取 clientSecret
    this.http.get("http://localhost:8080/api/payment/intent/clientSecret", {responseType:'text'}).subscribe(secret => {
      this.clientSecret = secret;

      // 2. 初始化 Stripe Elements
      const appearance = { theme: 'stripe' };
      this.elements = Stripe(this.clientSecret).elements({ appearance, clientSecret: this.clientSecret });

      // 3. 挂载 Payment Element
      // 注意:这里使用 'payment' 而不是 'card',因为 Payment Element 是更推荐的集成方式
      // 它会自动处理各种支付方式的UI,包括卡片。
      this.paymentElement = this.elements.create("payment");
      this.paymentElement.mount("#payment-element");

      // 可选:挂载 Link Authentication Element
      const linkAuthenticationElement = this.elements.create("linkAuthentication");
      linkAuthenticationElement.mount("#link-authentication-element");
      linkAuthenticationElement.on('change', (event:any) => {
          this.email = event.value.email;
      });
    });
  }

  async confirmPayment() {
    if (!this.elements || !this.clientSecret) {
      console.error("Stripe Elements or clientSecret not initialized.");
      return;
    }

    // 4. 确认支付意图
    // Stripe.confirmPayment() 是新版推荐的确认方式
    // 它会自动处理 3D Secure 等强客户认证流程
    const { error, paymentIntent } = await Stripe(this.clientSecret).confirmPayment({
        elements: this.elements,
        confirmParams: {
            // 确保 return_url 指向您的应用中处理支付结果的页面
            return_url: 'http://localhost:4200/payment-success', // 示例:支付成功后的跳转URL
            // 可选:设置账单详情,如果 Payment Element 没有自动收集
            // billing_details: { name: 'Barack Obama', email: this.email }
        },
        redirect: 'if_required' // 自动处理重定向(如3D Secure)
    });

    if (error) {
      // 显示错误信息给用户
      console.error("Payment confirmation failed:", error.message);
      // const messageContainer = document.querySelector('#payment-message');
      // if (messageContainer) messageContainer.textContent = error.message;
    } else if (paymentIntent.status === 'succeeded') {
      console.log("Payment succeeded!", paymentIntent);
      // 支付成功,此时 PaymentMethod 已经与 PaymentIntent 关联并可能已保存
      // 您可以在这里进行后续的业务逻辑,例如更新订单状态
      // paymentIntent.payment_method 将包含已保存的 PaymentMethod ID (pm_xxx)
      console.log("Saved PaymentMethod ID:", paymentIntent.payment_method);
    } else {
        console.log("Payment status:", paymentIntent.status);
        // 处理其他状态,如 'requires_action'(Stripe.confirmPayment() 通常会处理重定向)
    }
  }

  // testCreateCard() 方法可以替换为 confirmPayment()
  // @deprecated: testCreateCard 逻辑已合并到 confirmPayment
  // testCreateCard() { /* ... */ }
}
登录后复制

关键点:

  • 使用elements.create("payment")创建Payment Element,它能灵活处理多种支付方式。
  • 使用Stripe(clientSecret).confirmPayment()来确认支付。这个方法会自动处理3D Secure等强客户认证流程,并在必要时进行页面重定向。
  • 当PaymentIntent成功完成(status: 'succeeded')时,如果后端设置了setup_future_usage,Stripe会自动保存此支付方式,并将其ID关联到PaymentIntent或指定的Customer。

4. 复用已保存的 PaymentMethod

一旦您通过PaymentIntent或SetupIntent保存了PaymentMethod,并将其关联到Customer对象,您就可以在未来的支付中复用它,无需客户再次输入卡信息。

4.1 后端实现:使用已保存的 PaymentMethod 创建 PaymentIntent

当客户选择使用已保存的支付方式时,您的后端需要使用该PaymentMethod ID和Customer ID来创建新的PaymentIntent。

// Spring Boot (Java) 示例 - 使用已保存的 PaymentMethod 创建 PaymentIntent
import com.stripe.Stripe;
import com.stripe.model.PaymentIntent;
import com.stripe.param.PaymentIntentCreateParams;

public class PaymentService {

    public PaymentIntent createPaymentIntentWithSavedMethod(long amount, String currency, String customerId, String paymentMethodId) throws StripeException {
        Stripe.apiKey = "YOUR_STRIPE_SECRET_KEY";

        PaymentIntentCreateParams params = PaymentIntentCreateParams.builder()
            .setAmount(amount)
            .setCurrency(currency)
            .setCustomer(customerId) // 关联到客户
            .setPaymentMethod(paymentMethodId) // 使用已保存的 PaymentMethod ID
            .setConfirm(true) // 立即确认支付
            .setOffSession(true) // 如果是离线支付,设置为 true
            .build();

        PaymentIntent paymentIntent = PaymentIntent.create(params);
        return paymentIntent;
    }
}
登录后复制

setConfirm(true) 和 setOffSession(true) 的重要性:

  • setConfirm(true):指示Stripe在创建PaymentIntent后立即尝试确认支付。
  • setOffSession(true):表示此支付是在客户不在场的情况下进行的。如果支付需要客户交互(如3D Secure),而off_session为true,Stripe可能会拒绝支付或要求额外的处理。因此,确保您保存的PaymentMethod适合离线使用,或者在需要时引导客户完成额外的认证。

4.2 前端实现:触发复用支付

前端通常会展示客户已保存的支付方式列表。当客户选择其中一个时,前端将相应的PaymentMethod ID和Customer ID发送给后端,由后端发起支付。

// Angular Component - 触发复用支付的示例方法
// 假设您已经获取了客户的 PaymentMethod 列表
import { HttpClient } from '@angular/common/http';

export class AppComponent {
  // ... 其他属性

  constructor(private http: HttpClient) {}

  // 假设从后端获取了客户的 PaymentMethod 列表
  savedPaymentMethods: any[] = [
    { id: 'pm_123abc', brand: 'Visa', last4: '4242' },
    { id: 'pm_456def', brand: 'MasterCard', last4: '5555' }
  ];
  currentCustomerId: string = 'cus_Gxxx'; // 假设已获取客户ID

  useSavedCard(paymentMethodId: string) {
    const payload = {
      amount: 1000, // 支付金额 (美分)
      currency: 'usd',
      customerId: this.currentCustomerId,
      paymentMethodId: paymentMethodId
    };

    this.http.post("http://localhost:8080/api/payment/intent/reuse", payload).subscribe(
      (response: any) => {
        console.log("Payment with saved card successful:", response);
        // 根据 PaymentIntent 的状态处理结果
        if (response.status === 'succeeded') {
          console.log("Payment succeeded with saved card!");
          // 更新UI,显示支付成功信息
        } else if (response.status === 'requires_action') {
          // 如果需要额外的客户操作(如3D Secure),前端需要处理重定向
          // 这通常只在 off_session 为 false 或 PaymentMethod 不支持离线支付时发生
          window.location.href = response.next_action.redirect_to_url.url;
        }
      },
      error => {
        console.error("Error using saved card:", error);
        // 显示错误信息
      }
    );
  }
}
登录后复制

5. 注意事项与最佳实践

  • PCI DSS 合规性:再次强调,不要自行存储敏感卡数据。始终使用Stripe提供的安全机制。
  • 用户体验:清晰地告知用户他们的支付信息将被保存以供未来使用,并提供管理(添加/删除)已保存支付方式的界面。
  • 错误处理:在前端和后端都实现健壮的错误处理机制。Stripe API调用可能会失败,或者支付可能需要额外的用户交互(如3D Secure)。
  • 客户管理:为每个客户创建一个Customer对象,并将他们所有的PaymentMethod关联到该Customer。这有助于您管理客户的支付历史和偏好。
  • 测试:在沙盒(Test Mode)环境中充分测试您的支付流程,包括首次支付、保存卡片、复用卡片以及各种失败场景(如卡片拒绝、3D Secure挑战)。
  • Stripe Webhooks:对于异步事件(如支付成功、退款、争议等),强烈建议使用Stripe Webhooks。Webhooks可以确保您的系统及时收到Stripe的通知,并更新订单状态,而不是仅仅依赖前端的跳转结果。

总结

通过Stripe的PaymentIntent API结合PaymentMethod和Customer对象,您可以安全、高效地实现银行卡信息的保存和复用功能。这不仅提升了用户体验,也确保了您的应用程序符合PCI DSS标准,避免了处理敏感支付数据的风险。始终遵循Stripe的最佳实践,将敏感数据处理交给专业的支付服务商,从而专注于您的核心业务逻辑。

以上就是Stripe PaymentIntent API:安全地保存和复用银行卡信息的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号