
在处理银行卡数据时,首要且最关键的原则是遵守支付卡行业数据安全标准(PCI DSS)。PCI DSS旨在保护持卡人数据,其要求非常严格。除非您的组织达到了PCI DSS一级服务提供商或SAQ D级别,否则绝不应在自己的服务器上存储原始银行卡号、有效期或CVV等敏感信息。自行存储这些数据不仅风险巨大,还可能导致严重的法律和财务后果。
Stripe作为PCI DSS一级服务提供商,提供了安全的方式来处理和存储银行卡信息。最佳实践是让Stripe来处理所有敏感数据,您只需存储Stripe返回的非敏感标识符(如PaymentMethod ID)。
Stripe提供了PaymentMethod和Customer对象来安全地管理客户的支付信息。
Stripe允许您在创建PaymentIntent时,同时收集并保存客户的支付方式,以供未来使用。这通过在创建PaymentIntent时设置setup_future_usage参数来实现。
当您的前端请求创建一个支付意图时,后端(例如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。
前端(例如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() { /* ... */ }
}关键点:
一旦您通过PaymentIntent或SetupIntent保存了PaymentMethod,并将其关联到Customer对象,您就可以在未来的支付中复用它,无需客户再次输入卡信息。
当客户选择使用已保存的支付方式时,您的后端需要使用该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) 的重要性:
前端通常会展示客户已保存的支付方式列表。当客户选择其中一个时,前端将相应的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);
// 显示错误信息
}
);
}
}通过Stripe的PaymentIntent API结合PaymentMethod和Customer对象,您可以安全、高效地实现银行卡信息的保存和复用功能。这不仅提升了用户体验,也确保了您的应用程序符合PCI DSS标准,避免了处理敏感支付数据的风险。始终遵循Stripe的最佳实践,将敏感数据处理交给专业的支付服务商,从而专注于您的核心业务逻辑。
以上就是Stripe PaymentIntent API:安全地保存和复用银行卡信息的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号