Stripe:未找到与使用 Django 的有效负载的预期签名相匹配的签名

Stripe: No signatures found matching the expected signature for payload using Django

我在 Stripe 调用定义的 Web 挂钩时遇到以下错误

No signatures found matching the expected signature for payload

我正在关注这篇文章:https://stripe.com/docs/billing/subscriptions/checkout#provision-and-monitor

我有以下代码:

@csrf_exempt
def saaswebhookview(request):
    try:
        stripe.api_key = settings.STRIPE_SECRET_KEY
        webhook_secret = 'stripe_key'
        request_data = request.POST
        if webhook_secret:
            try:
                signature = request.headers.get('stripe-signature')
                # signature = request.META['stripe-signature']
                event = stripe.Webhook.construct_event(
                    payload=request.POST, sig_header=signature, secret=webhook_secret)
                data = event['data']
            except Exception as e:
                print(str(e))
                return JsonResponse({'status': 'error', 'error': str(e)})
            event_type = event['type']
        else:
            data = request_data['data']
            event_type = request_data['type']
        data_object = data['object']
        if event_type == 'checkout.session.completed':
            print(data)
        elif event_type == 'invoice.paid':
            print(data)
        elif event_type == 'invoice.payment_failed':
            print(data)
        else:
            print('Unhandled event type {}'.format(event_type))
        return JsonResponse({'status': 'success'}, safe=False)
    except Exception as e:
        return JsonResponse({'status': 'success', 'error': str(e)}, safe=False)

但奇怪的是,这会抛出错误,不知道为什么?

Stripe 库需要用于签名验证的 webhook 请求的原始主体才能工作。看起来您提供的是 request.POST,这是正文的修改版本。

如果您改用 request.body,它应该可以正常工作。

使用生成的签名

验证您的 Stripe Webhook API 的脚本
import hmac
import time
from hashlib import sha256

import requests
import stripe

webhook_url = 'https://your-site/api/stripe/webhook/'
stripe_secret = 'YOUR_STRIPE_WEBHOOK_SIGN_SECRET'  # whsec_..
webhook_json_file = 'PATH_TO_JSON_FILE_WITH_WH_DATA/webhook_example.json'


def generate_stripe_signature_header(payload: str):
    timestamp_utc = int(time.time())
    signed_payload = "%d.%s" % (timestamp_utc, payload)
    v1_sig = compute_signature(signed_payload, secret=stripe_secret)
    return f't={timestamp_utc},v1={v1_sig}'


def compute_signature(payload: str, secret):
    """Take from stripe"""
    mac = hmac.new(
        secret.encode("utf-8"),
        msg=payload.encode("utf-8"),
        digestmod=sha256,
    )
    return mac.hexdigest()


with open(webhook_json_file, 'r') as f:
    payload = f.read()

signature = generate_stripe_signature_header(payload=payload)

headers = {
    'STRIPE-SIGNATURE': signature,  
    'Content-Type': 'application/json',
}

session = requests.Session()
session.headers.update(**headers)
response = session.post(webhook_url, data=payload)

print(response.content)
print(response.status_code)
response.raise_for_status()

P.S. 如果您想将它用于 单元测试 / Django 测试客户端,需要在签名头添加HTTP_前缀

signature = generate_stripe_signature_header(payload=payload)
headers = {
    'HTTP_STRIPE-SIGNATURE': signature,  
    'Content-Type': 'application/json',
}
self.client.post(webhook_url, data=payload, **headers)

就我而言,为了解决我的问题,我对正文进行了解码:

payload = request.body.decode('utf-8')