0

0

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

聖光之護

聖光之護

发布时间:2025-07-15 23:02:33

|

532人浏览过

|

来源于php中文网

原创

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创建时设置。

Farfalle
Farfalle

Farfalle.dev 是一个开源的 AI 搜索引擎,定位为 Perplexity 的自托管替代品。

下载
// 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的最佳实践,将敏感数据处理交给专业的支付服务商,从而专注于您的核心业务逻辑。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

115

2025.08.06

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

33

2026.01.26

spring boot框架优点
spring boot框架优点

spring boot框架的优点有简化配置、快速开发、内嵌服务器、微服务支持、自动化测试和生态系统支持。本专题为大家提供spring boot相关的文章、下载、课程内容,供大家免费下载体验。

135

2023.09.05

spring框架有哪些
spring框架有哪些

spring框架有Spring Core、Spring MVC、Spring Data、Spring Security、Spring AOP和Spring Boot。详细介绍:1、Spring Core,通过将对象的创建和依赖关系的管理交给容器来实现,从而降低了组件之间的耦合度;2、Spring MVC,提供基于模型-视图-控制器的架构,用于开发灵活和可扩展的Web应用程序等。

390

2023.10.12

Java Spring Boot开发
Java Spring Boot开发

本专题围绕 Java 主流开发框架 Spring Boot 展开,系统讲解依赖注入、配置管理、数据访问、RESTful API、微服务架构与安全认证等核心知识,并通过电商平台、博客系统与企业管理系统等项目实战,帮助学员掌握使用 Spring Boot 快速开发高效、稳定的企业级应用。

70

2025.08.19

Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性
Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性

Spring Boot 是一个基于 Spring 框架的 Java 开发框架,它通过 约定优于配置的原则,大幅简化了 Spring 应用的初始搭建、配置和开发过程,让开发者可以快速构建独立的、生产级别的 Spring 应用,无需繁琐的样板配置,通常集成嵌入式服务器(如 Tomcat),提供“开箱即用”的体验,是构建微服务和 Web 应用的流行工具。

35

2025.12.22

Java Spring Boot 微服务实战
Java Spring Boot 微服务实战

本专题深入讲解 Java Spring Boot 在微服务架构中的应用,内容涵盖服务注册与发现、REST API开发、配置中心、负载均衡、熔断与限流、日志与监控。通过实际项目案例(如电商订单系统),帮助开发者掌握 从单体应用迁移到高可用微服务系统的完整流程与实战能力。

159

2025.12.24

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

183

2023.12.04

java 字符串格式化
java 字符串格式化

本专题整合了java如何进行字符串格式化相关教程、使用解析、方法详解等等内容。阅读专题下面的文章了解更多详细教程。

0

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.1万人学习

CSS教程
CSS教程

共754课时 | 25.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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