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

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) 示例 - 创建 PaymentIntentimport 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创建时设置。

// 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.jsdeclare 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 创建 PaymentIntentimport 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:安全地保存和复用银行卡信息的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/136533.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月29日 23:56:31
下一篇 2025年11月30日 00:42:16

相关推荐

  • 怎样用免费工具美化PPT_免费美化PPT的实用方法分享

    利用KIMI智能助手可免费将PPT美化为科技感风格,但需核对文字准确性;2. 天工AI擅长优化内容结构,提升逻辑性,适合高质量内容需求;3. SlidesAI支持语音输入与自动排版,操作便捷,利于紧急场景;4. Prezo提供多种模板,自动生成图文并茂幻灯片,适合学生与初创团队。 如果您有一份内容完…

    2025年12月6日 软件教程
    000
  • Pages怎么协作编辑同一文档 Pages多人实时协作的流程

    首先启用Pages共享功能,点击右上角共享按钮并选择“添加协作者”,设置为可编辑并生成链接;接着复制链接通过邮件或社交软件发送给成员,确保其使用Apple ID登录iCloud后即可加入编辑;也可直接在共享菜单中输入邮箱地址定向邀请,设定编辑权限后发送;最后在共享面板中管理协作者权限,查看实时在线状…

    2025年12月6日 软件教程
    100
  • 咸鱼遇到“只退款不退货”的买家怎么办_咸鱼处理只退款不退货方法

    先与买家协商解决,要求其按规则退货退款,并保留聊天记录;若协商无效,申请平台介入并提交发货、签收及沟通等证据;若平台处理不利且金额较大,可依法提起民事诉讼,主张买家违反《民法典》合同规定,追回货款。 如果您在咸鱼平台出售手机后,买家申请“仅退款不退货”,这可能导致您既损失商品又损失资金。以下是应对该…

    2025年12月6日 软件教程
    000
  • REDMI K90系列正式发布,售价2599元起!

    10月23日,redmi k90系列正式亮相,推出redmi k90与redmi k90 pro max两款新机。其中,redmi k90搭载骁龙8至尊版处理器、7100mah大电池及100w有线快充等多项旗舰配置,起售价为2599元,官方称其为k系列迄今为止最完整的标准版本。 图源:REDMI红米…

    2025年12月6日 行业动态
    200
  • 买家网购苹果手机仅退款不退货遭商家维权,法官调解后支付货款

    10 月 24 日消息,据央视网报道,近年来,“仅退款”服务逐渐成为众多网购平台的常规配置,但部分消费者却将其当作“免费试用”的手段,滥用规则谋取私利。 江苏扬州市民李某在某电商平台购买了一部苹果手机,第二天便以“不想要”为由在线申请“仅退款”,当时手机尚在物流运输途中。第三天货物送达后,李某签收了…

    2025年12月6日 行业动态
    000
  • Linux中如何安装Nginx服务_Linux安装Nginx服务的完整指南

    首先更新系统软件包,然后通过对应包管理器安装Nginx,启动并启用服务,开放防火墙端口,最后验证欢迎页显示以确认安装成功。 在Linux系统中安装Nginx服务是搭建Web服务器的第一步。Nginx以高性能、低资源消耗和良好的并发处理能力著称,广泛用于静态内容服务、反向代理和负载均衡。以下是在主流L…

    2025年12月6日 运维
    000
  • Linux journalctl与systemctl status结合分析

    先看 systemctl status 确认服务状态,再用 journalctl 查看详细日志。例如 nginx 启动失败时,systemctl status 显示 Active: failed,journalctl -u nginx 发现端口 80 被占用,结合两者可快速定位问题根源。 在 Lin…

    2025年12月6日 运维
    100
  • 华为新机发布计划曝光:Pura 90系列或明年4月登场

    近日,有数码博主透露了华为2025年至2026年的新品规划,其中pura 90系列预计在2026年4月发布,有望成为华为新一代影像旗舰。根据路线图,华为将在2025年底至2026年陆续推出mate 80系列、折叠屏新机mate x7系列以及nova 15系列,而pura 90系列则将成为2026年上…

    2025年12月6日 行业动态
    100
  • Linux如何优化系统性能_Linux系统性能优化的实用方法

    优化Linux性能需先监控资源使用,通过top、vmstat等命令分析负载,再调整内核参数如TCP优化与内存交换,结合关闭无用服务、选用合适文件系统与I/O调度器,持续按需调优以提升系统效率。 Linux系统性能优化的核心在于合理配置资源、监控系统状态并及时调整瓶颈环节。通过一系列实用手段,可以显著…

    2025年12月6日 运维
    000
  • 曝小米17 Air正在筹备 超薄机身+2亿像素+eSIM技术?

    近日,手机行业再度掀起超薄机型热潮,三星与苹果已相继推出s25 edge与iphone air等轻薄旗舰,引发市场高度关注。在此趋势下,多家国产厂商被曝正积极布局相关技术,加速抢占这一细分赛道。据业内人士消息,小米的超薄旗舰机型小米17 air已进入筹备阶段。 小米17 Pro 爆料显示,小米正在评…

    2025年12月6日 行业动态
    000
  • 「世纪传奇刀片新篇」飞利浦影音双11声宴开启

    百年声学基因碰撞前沿科技,一场有关声音美学与设计美学的影音狂欢已悄然引爆2025“双十一”! 当绝大多数影音数码品牌还在价格战中挣扎时,飞利浦影音已然开启了一场跨越百年的“声”活革命。作为拥有深厚技术底蕴的音频巨头,飞利浦影音及配件此次“双十一”精准聚焦“传承经典”与“设计美学”两大核心,为热爱生活…

    2025年12月6日 行业动态
    000
  • 荣耀手表5Pro 10月23日正式开启首销国补优惠价1359.2元起售

    荣耀手表5pro自9月25日开启全渠道预售以来,市场热度持续攀升,上市初期便迎来抢购热潮,一度出现全线售罄、供不应求的局面。10月23日,荣耀手表5pro正式迎来首销,提供蓝牙版与esim版两种选择。其中,蓝牙版本的攀登者(橙色)、开拓者(黑色)和远航者(灰色)首销期间享受国补优惠价,到手价为135…

    2025年12月6日 行业动态
    000
  • 环境搭建docker环境下如何快速部署mysql集群

    使用Docker Compose部署MySQL主从集群,通过配置文件设置server-id和binlog,编写docker-compose.yml定义主从服务并组网,启动后创建复制用户并配置主从连接,最后验证数据同步是否正常。 在Docker环境下快速部署MySQL集群,关键在于合理使用Docker…

    2025年12月6日 数据库
    000
  • Xbox删忍龙美女角色 斯宾塞致敬板垣伴信被喷太虚伪

    近日,海外游戏推主@HaileyEira公开发表言论,批评Xbox负责人菲尔·斯宾塞不配向已故的《死或生》与《忍者龙剑传》系列之父板垣伴信致敬。她指出,Xbox并未真正尊重这位传奇制作人的创作遗产,反而在宣传相关作品时对内容进行了审查和删减。 所涉游戏为年初推出的《忍者龙剑传2:黑之章》,该作采用虚…

    2025年12月6日 游戏教程
    000
  • 如何在mysql中分析索引未命中问题

    答案是通过EXPLAIN分析执行计划,检查索引使用情况,优化WHERE条件写法,避免索引失效,结合慢查询日志定位问题SQL,并根据查询模式合理设计索引。 当 MySQL 查询性能下降,很可能是索引未命中导致的。要分析这类问题,核心是理解查询执行计划、检查索引设计是否合理,并结合实际数据访问模式进行优…

    2025年12月6日 数据库
    000
  • VSCode入门:基础配置与插件推荐

    刚用VSCode,别急着装一堆东西。先把基础设好,再按需求加插件,效率高还不卡。核心就三步:界面顺手、主题舒服、功能够用。 设置中文和常用界面 打开软件,左边活动栏有五个图标,点最下面那个“扩展”。搜索“Chinese”,装上官方出的“Chinese (Simplified) Language Pa…

    2025年12月6日 开发工具
    000
  • php查询代码怎么写_php数据库查询语句编写技巧与实例

    在PHP中进行数据库查询,最常用的方式是使用MySQLi或PDO扩展连接MySQL数据库。下面介绍基本的查询代码写法、编写技巧以及实用示例,帮助你高效安全地操作数据库。 1. 使用MySQLi进行查询(面向对象方式) 这是较为推荐的方式,适合大多数中小型项目。 // 创建连接$host = ‘loc…

    2025年12月6日 后端开发
    000
  • php数据库如何实现数据缓存 php数据库减少查询压力的方案

    答案:PHP结合Redis等内存缓存系统可显著提升Web应用性能。通过将用户信息、热门数据等写入内存缓存并设置TTL,先查缓存未命中再查数据库,减少数据库压力;配合OPcache提升脚本执行效率,文件缓存适用于小型项目,数据库缓冲池优化和读写分离进一步提升性能,推荐Redis为主并防范缓存穿透与雪崩…

    2025年12月6日 后端开发
    000
  • 重现iPhone X颠覆性时刻!苹果2027年跳过19命名iPhone 20

    10月23日,有消息称,苹果或将再次调整iPhone的发布节奏,考虑跳过“iPhone 19”,并于2027年直接推出“iPhone 20”系列。 此举据传是为了庆祝初代iPhone发布二十周年,同时开启新一轮的设计革新,目标是复刻2017年iPhone X带来的划时代变革。 据悉,苹果或将告别长期…

    2025年12月6日 手机教程
    000
  • 优化PDF中下载链接的URL显示:利用HTML title 属性

    在pdf文档中,当包含下载链接时,完整的url路径通常会在鼠标悬停时或直接显示在链接文本中,这可能不符合预期。本文将探讨为何传统方法如`.htaccess`重写或javascript不适用于pdf环境,并提出一种利用html “ 标签的 `title` 属性来定制链接悬停显示文本的解决方…

    2025年12月6日 后端开发
    000

发表回复

登录后才能评论
关注微信