如何借助Stripe Node.js Webhook拦截特定邮箱域名的支付?
解决方案:拦截黑名单邮箱域名的Stripe支付链接欺诈
可行方案1:监听checkout.session.created事件,提前过期违规会话
Stripe提供checkout.session.created Webhook事件,触发时机是用户打开支付链接、结账会话生成时。你可以在这个阶段检查用户邮箱域名,匹配黑名单后直接过期会话,阻止用户完成支付。
实现步骤:
- 在Stripe Dashboard的Webhook设置中,启用
checkout.session.created事件并配置你的Webhook端点。 - 在Node.js的Webhook处理逻辑中,提取会话中的用户邮箱,解析域名并对比黑名单。
- 匹配黑名单时,调用
checkout.sessions.expire()API过期当前会话。
代码示例:
const stripe = require('stripe')('你的Stripe密钥'); // Webhook端点处理函数 app.post('/stripe-webhook', async (req, res) => { const sig = req.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent( req.rawBody, sig, '你的Webhook签名密钥' ); } catch (err) { return res.status(400).send(`Webhook验证失败: ${err.message}`); } // 处理checkout.session.created事件 if (event.type === 'checkout.session.created') { const session = event.data.object; const userEmail = session.customer_details?.email; if (!userEmail) { return res.json({ received: true }); } // 提取邮箱域名 const emailDomain = userEmail.split('@')[1]; // 你的黑名单域名列表 const blacklistedDomains = ['fraud-domain.com', 'test-card.example']; if (blacklistedDomains.includes(emailDomain)) { try { // 过期违规会话 await stripe.checkout.sessions.expire(session.id); console.log(`已过期会话 ${session.id},对应黑名单域名:${emailDomain}`); } catch (err) { console.error('过期会话失败:', err); } } } res.json({ received: true }); });
可行方案2:配置支付链接为手动扣款,拦截违规支付Intent
通过API创建支付链接时,设置payment_intent_data.capture_method: 'manual',让支付仅完成授权、不自动扣款。之后监听payment_intent.created事件,检查用户邮箱域名,匹配黑名单时取消支付Intent,阻止后续扣款操作。
实现步骤:
- 通过Stripe API创建支付链接,指定手动扣款模式。
- 启用
payment_intent.createdWebhook事件,在处理逻辑中关联客户邮箱并检查黑名单。 - 匹配黑名单时,调用
paymentIntents.cancel()取消支付Intent。
代码示例:
创建手动扣款模式的支付链接
const createPaymentLink = async () => { const paymentLink = await stripe.paymentLinks.create({ line_items: [ { price: '你的订阅价格ID', quantity: 1, }, ], payment_intent_data: { capture_method: 'manual', // 设置为手动扣款 }, }); return paymentLink; };
Webhook处理支付Intent创建事件
// 接上文Webhook处理函数 if (event.type === 'payment_intent.created') { const paymentIntent = event.data.object; // 获取关联的客户信息 const customer = await stripe.customers.retrieve(paymentIntent.customer); const userEmail = customer.email; if (!userEmail) { return res.json({ received: true }); } const emailDomain = userEmail.split('@')[1]; const blacklistedDomains = ['fraud-domain.com', 'test-card.example']; if (blacklistedDomains.includes(emailDomain)) { try { await stripe.paymentIntents.cancel(paymentIntent.id); console.log(`已取消支付Intent ${paymentIntent.id},对应黑名单域名:${emailDomain}`); } catch (err) { console.error('取消支付Intent失败:', err); } } }
注意事项
- 方案1属于事前拦截,用户会直接看到会话过期提示,体验上更直接;方案2是授权后拦截,适合需要保留授权记录的场景。
- 如果你的支付链接是通过Stripe Dashboard创建的,无法设置手动扣款模式,必须通过API创建。
- 确保Webhook端点的网络延迟足够低,避免在用户完成支付后才触发过期/取消操作。
内容的提问来源于stack exchange,提问作者thdoan
相关产品推荐
相关产品推荐

