您好,我想使用 Stripe 以便用户可以创建订阅。我对客户端密钥感到困惑。我有 api 和机密的测试密钥,我也有 api 和机密的实时密钥,并且我有我创建的订阅服务的产品密钥。
另外,我还拥有安装 cli 并通过终端登录到 stripe 后创建的 CLI 密钥。
但是我没有客户端秘密,而且我很担心,因为当我获得一个客户端秘密时,我不希望将其放在客户端服务器上。
我使用离子 5 角 14 电容器 5,以 NODE.JS 和 PHP 作为后端。我的服务器上有一个名为 stripe 的文件夹,但我在那里没有看到任何密钥。
组件.ts
import { Component, AfterViewInit, ElementRef, ViewChild } from '@angular/core';
import { Router } from "@angular/router";
import { UserData } from 'src/app/services/user-data/user-data';
import {
loadStripe,
Stripe,
StripeElements,
StripeCardElement,
StripeElementsOptions,
StripeElement,
} from '@stripe/stripe-js';
@Component({
selector: 'app-subscription',
templateUrl: 'subscription.page.html',
styleUrls: ['subscription.page.scss'],
})
export class SubscriptionPage implements AfterViewInit {
stripe: Stripe;
elements: StripeElements;
paymentElement: StripeElement;
appearance: StripeElementsOptions['appearance'] = {
theme: 'stripe',
variables: {
colorPrimary: '#0570de',
colorBackground: '#ffffff',
colorText: '#30313d',
colorDanger: '#df1b41',
fontFamily: 'Ideal Sans, system-ui, sans-serif',
spacingUnit: '2px',
borderRadius: '4px',
// Define other custom styling variables as needed
},
};
menuOpenCopyright: boolean = false;
user: any = {};
email: string = '';
uid: string = '';
modalOpen: boolean = false;
cardInputFocused: boolean = false;
cardDetail: any = {
name: '',
cardNumber: '',
expiryDate: '',
securityCode: '',
};
constructor(
public router: Router,
public userData: UserData,
) {
this.user = this.userData.getUserData();
this.uid = this.user.uid;
this.email = this.user.email;
}
ngAfterViewInit() {
// Initialize Stripe with your publishable key
this.initializeStripe().then(() => {
// Create the card element after initializing Stripe
this.createPaymentElement();
});
}
async initializeStripe() {
const stripePromise = loadStripe('sk_live_51HiSxxxxxxxxx'); // Replace with your actual publishable key
this.stripe = await stripePromise;
}
createPaymentElement() {
if (!this.stripe) {
console.error('Stripe is not initialized.');
return;
}
this.elements = this.stripe.elements({
clientSecret: 'sk_live_51HiSxxxxxxxxx', // Replace with your actual client secret
});
// Create the payment element
const paymentElementOptions = {
// Add any specific options for the payment element
};
this.paymentElement = this.elements.create('payment', paymentElementOptions);
// Mount the payment element to the DOM
this.paymentElement.mount('#payment-element');
}
async subscribe() {
try {
event.stopPropagation();
console.log('Card Number: ' + this.cardDetail.cardNumber);
// Tokenize the card details using the new cardElement
const { token, error } = await this.stripe.createToken(this.paymentElement, {
name: this.cardDetail.name,
address_line1: '', // Include any relevant address information here
address_city: '', // Include city information here
address_state: '', // Include state information here
address_zip: '', // Include ZIP code here
address_country: '', // Include country information here
});
if (!error) {
console.log('Tokenization successful');
const paymentData = {
email: this.cardDetail.email,
token: token.id,
uid: this.uid,
name: this.cardDetail.name,
business: this.cardDetail.business
};
// Send the token and user's email to your server
this.userData.createCustomer(paymentData).subscribe((customerResponse: any) => {
if (customerResponse.success) {
const customerId = customerResponse.customer.id;
console.log('Customer created:', customerResponse.customer);
this.userData.createSetupIntent(customerId).subscribe((setupIntentResponse: any) => {
if (setupIntentResponse.success) {
const setupIntentClientSecret = setupIntentResponse.setupIntent.client_secret;
// Create a subscription with the saved payment method
const planId = 'price_1O2VVjGozbMWFnurNiXUurH7'; // Replace with your actual pricing plan ID
this.userData.createSubscription(customerId, planId).subscribe((subscriptionResponse: any) => {
if (subscriptionResponse.success) {
console.log('Subscription successful:', subscriptionResponse.subscription);
} else {
console.error(subscriptionResponse.error);
}
});
} else {
console.error(setupIntentResponse.error);
}
});
} else {
console.error(customerResponse.error);
console.error('Error creating customer:', customerResponse.error);
}
});
} else {
console.error('Tokenization error:', error);
// Handle the error if tokenization fails
console.error(error);
}
} catch (error) {
console.error('Error in subscribe:', error);
console.error(error);
}
}
在控制台上我得到
ERROR Error: Uncaught (in promise): IntegrationError: Invalid value for elements(): clientSecret should be a client secret of the form ${id}_secret_${secret}. You specified: sk_live_51HiSUxxxxxxx.
IntegrationError: Invalid value for elements(): clientSecret should be a client secret of the form ${id}_secret_${secret}. You specified: sk_live_51HiSUxxxxx.
at ne (v3/:1:178295)
at re (v3/:1:178367)
at new t (v3/:1:328546)
at e.<anonymous> (v3/:1:382147)
at e.<anonymous> (v3/:1:84831)
at e.o (v3/:1:421236)
at SubscriptionPage.createPaymentElement (subscription.page.ts:82:33)
at subscription.page.ts:67:12
at push.96084._ZoneDelegate.invoke (zone.js:409:1)
at Object.onInvoke (core.mjs:25450:1)
at resolvePromise (zone.js:1262:1)
at zone.js:1333:1
at push.96084._ZoneDelegate.invokeTask (zone.js:443:1)
at Object.onInvokeTask (core.mjs:25437:1)
at push.96084._ZoneDelegate.invokeTask (zone.js:442:1)
at push.96084.Zone.runTask (zone.js:214:1)
at drainMicroTaskQueue (zone.js:632:1)
at push.96084.ZoneTask.invokeTask [as invoke] (zone.js:529:1)
at invokeTask (zone.js:1727:1)
at globalCallback (zone.js:1758:1)
有什么帮助吗?
client_secret 是从通过订阅创建的 PaymentIntent 中获取的。因此,基本上,您在后端创建订阅,当您这样做时,您需要使用
payment_behavior: 'default_incomplete'
并展开 latest_invoice.payment_intent
,以便您可以访问 PaymentIntent 的 client_secret。然后,您将该 client_secret 传递到前端以初始化 Elements。有关此流程的完整文档,请参阅:https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements。