如何通过Stripe API在服务端验证用户是否购买特定产品?
验证Stripe购买状态的正确方案
不要依赖前端传入的paystate参数,这种方式完全不可靠。正确的做法是利用Stripe Checkout Session的内置机制,通过服务端验证真实的支付会话。
步骤1:修改Checkout Session创建逻辑
创建会话时,在success_url中加入Stripe提供的{CHECKOUT_SESSION_ID}占位符,这样跳转时会自动携带真实的会话ID:
const session = await stripe.checkout.sessions.create({ line_items: list, mode: 'payment', success_url: `${process.env.NEXT_URL}/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${process.env.NEXT_URL}/cancel`, });
步骤2:在getServerSideProps中验证会话
服务端通过会话ID直接向Stripe API查询真实的支付状态,同时验证用户和产品信息:
export async function getServerSideProps(context) { const { session_id } = context.query; // 没有会话ID直接跳转到取消页 if (!session_id) { return { redirect: { destination: '/cancel', permanent: false } }; } try { // 检索会话并展开支付意向、商品明细 const session = await stripe.checkout.sessions.retrieve(session_id, { expand: ['payment_intent', 'line_items'], }); // 1. 验证支付状态是否为已完成 if (session.payment_status !== 'paid') { return { redirect: { destination: '/cancel', permanent: false } }; } // 2. 验证当前用户邮箱与会话中的客户邮箱匹配(需从登录态获取当前用户邮箱) const currentUserEmail = "当前登录用户的邮箱"; // 替换为你的用户邮箱获取逻辑 if (session.customer_email !== currentUserEmail) { return { props: { hasPurchased: false, error: "用户身份不匹配" } }; } // 3. 验证是否购买了目标产品(替换为你的产品ID) const targetProductId = "你的特定产品ID"; const hasPurchasedTarget = session.line_items.data.some(item => item.price.product === targetProductId ); return { props: { hasPurchased: hasPurchasedTarget, orderDetails: { amount: session.amount_total, productName: session.line_items.data[0].description } } }; } catch (err) { // 会话不存在或API调用失败,跳转到取消页 console.error("验证错误:", err); return { redirect: { destination: '/cancel', permanent: false } }; } }
为什么你的原有代码无法获取购买记录?
- 查询对象错误:在
payment模式下,一次性支付的记录优先通过Checkout Session或Payment Intent查询,直接调用charges.list容易遗漏或过滤不到目标记录。如果一定要用charges.list,需要添加过滤条件:const charges = await stripe.charges.list({ customer: customerId, status: 'succeeded', // 只查成功的支付 limit: 100 // 扩大查询范围 }); - 会话关联更可靠:通过Checkout Session验证能直接关联到本次结账行为,避免查询用户所有历史订单的冗余,同时保证验证的唯一性和准确性。
关键注意事项
- 永远不要信任前端传入的任何支付状态参数,必须通过Stripe API做服务端验证
- 确保你的Stripe Secret Key存储在环境变量中,不要暴露在前端
- 测试模式下,可以使用Stripe提供的测试卡号(如
4242 4242 4242 4242)模拟支付成功场景
内容的提问来源于stack exchange,提问作者Coder
相关产品推荐
相关产品推荐

