值得一看
双11 12
广告
广告

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

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

温馨提示: 本文最后更新于2025-07-16 10:40:06,某些文章具有时效性,若有错误或已失效,请在下方留言或联系易赚网
文章版权声明 1 本网站名称: 创客网
2 本站永久网址:https://new.ie310.com
1 本文采用非商业性使用-相同方式共享 4.0 国际许可协议[CC BY-NC-SA]进行授权
2 本站所有内容仅供参考,分享出来是为了可以给大家提供新的思路。
3 互联网转载资源会有一些其他联系方式,请大家不要盲目相信,被骗本站概不负责!
4 本网站只做项目揭秘,无法一对一教学指导,每篇文章内都含项目全套的教程讲解,请仔细阅读。
5 本站分享的所有平台仅供展示,本站不对平台真实性负责,站长建议大家自己根据项目关键词自己选择平台。
6 因为文章发布时间和您阅读文章时间存在时间差,所以有些项目红利期可能已经过了,能不能赚钱需要自己判断。
7 本网站仅做资源分享,不做任何收益保障,创业公司上收费几百上千的项目我免费分享出来的,希望大家可以认真学习。
8 本站所有资料均来自互联网公开分享,并不代表本站立场,如不慎侵犯到您的版权利益,请联系79283999@qq.com删除。

本站资料仅供学习交流使用请勿商业运营,严禁从事违法,侵权等任何非法活动,否则后果自负!
THE END
喜欢就支持一下吧
点赞12赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容