我尝试在Stripe webhook端点中验证请求签名,但一直收到错误:
No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?
我已经尝试了多种解决方案,多种解析原始请求体的方法。我也试过手动验证HMAC信号。什么都没用。
我的环境:
Next.js 13.3.2 Stripe SDK 12.4.0
复制步骤:
1.在以下位置创建端点:/pages/api/p/test
代码:
import Stripe from 'stripe';
import { NextApiRequest, NextApiResponse } from 'next';
import safe from 'colors/safe';
import { buffer } from 'micro';
const handler = async (
req: NextApiRequest,
res: NextApiResponse
): Promise<void> => {
const stripe = new Stripe(process.env.STRIPE_SECRET as string, {
apiVersion: '2022-11-15',
});
const webhookSecret: string = "whsec_33244....";
if (req.method === 'POST') {
const sig = req.headers['stripe-signature'] as string;
const buf = await buffer(req);
const body = buf.toString();
let event: Stripe.Event;
try {
console.log(safe.bgGreen(body))
event = stripe.webhooks.constructEvent(body, sig, webhookSecret);
} catch (err) {
// On error, log and return the error message
console.log(`❌ Error message: ${err.message}`);
res.status(400).send(`Webhook Error: ${err.message}`);
return;
}
// Successfully constructed event
console.log('✅ Success:', event.id);
// Cast event data to Stripe object
if (event.type === 'payment_intent.succeeded') {
const stripeObject: Stripe.PaymentIntent = event.data
.object as Stripe.PaymentIntent;
console.log(`💰 PaymentIntent status: ${stripeObject.status}`);
} else if (event.type === 'charge.succeeded') {
const charge = event.data.object as Stripe.Charge;
console.log(`💵 Charge id: ${charge.id}`);
} else {
console.warn(`🤷♀️ Unhandled event type: ${event.type}`);
}
// Return a response to acknowledge receipt of the event
res.json({ received: true });
} else {
res.setHeader('Allow', 'POST');
res.status(405).end('Method Not Allowed');
}
};
export const config = {
api: {
bodyParser: false,
},
};
export default handler;
1.启动dev服务器并启动条带侦听器
stripe listen --forward-to localhost:3000/api/p/test
1.复制生成的webhook签名密钥并粘贴到代码中
1.启动模拟事件
stripe trigger payment_intent.succeeded
我在网上搜遍了所有的方法。我完全被难倒了。我正在使用微服务包中的buffer
,但我也在Stripe的文档中尝试了示例中的缓冲区功能。它似乎正确地解析了主体:
console.log(body)
{
"id": "evt_3NIzhvEcQkKxoTiV1xjEMh02",
"object": "event",
"api_version": "2022-11-15",
"created": 1686772219,
"data": {
"object": {
"id": "pi_3NIzhvEcQkKxoTiV1kuXEmH6",
"object": "payment_intent",
"amount": 2000,
"amount_capturable": 0,
"amount_details": {
"tip": {
}
},
"amount_received": 0,
"application": null,
"application_fee_amount": null,
"automatic_payment_methods": null,
"canceled_at": null,
"cancellation_reason": null,
"capture_method": "automatic",
"client_secret": "pi_3NIzhvEcQkKxoTiV1kuXEmH6_secret_ZRnfaga3uRF5EhNXE0KwZpDpp",
"confirmation_method": "automatic",
"created": 1686772219,
"currency": "usd",
"customer": null,
"description": "(created by Stripe CLI)",
"invoice": null,
"last_payment_error": null,
"latest_charge": null,
"livemode": false,
"metadata": {
},
"next_action": null,
"on_behalf_of": null,
"payment_method": null,
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
},
"payment_method_types": [
"card"
],
"processing": null,
"receipt_email": null,
"review": null,
"setup_future_usage": null,
"shipping": {
"address": {
"city": "San Francisco",
"country": "US",
"line1": "510 Townsend St",
"line2": null,
"postal_code": "94103",
"state": "CA"
},
"carrier": null,
"name": "Jenny Rosen",
"phone": null,
"tracking_number": null
},
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "requires_payment_method",
"transfer_data": null,
"transfer_group": null
}
},
"livemode": false,
"pending_webhooks": 2,
"request": {
"id": "req_MfPOwrw4MZsykJ",
"idempotency_key": "10108c32-75db-4e1e-abb3-b3b2673df025"
},
"type": "payment_intent.created"
}
如果有人有任何想法,我将不胜感激!
2条答案
按热度按时间zpqajqem1#
问题是Next.JS有一个中间件来处理请求的原始体。尝试为您的路线关闭bodyParser:https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config,否则您需要确保获得原始请求。
在将
body
传递给constructEvent()
之前,在端点中记录body
时,应该会看到一堆二进制(这就是缓冲区数据类型的样子)。这是一个迹象,你实际上有原始的身体。如果您看到JSON或字符串,那么您知道原始主体已被操作,并且您的Webhook签名验证将失败。aor9mmx12#
男孩我觉得愚蠢。我的测试密钥末尾缺少一个字符。😡