如何在Django/DRF中验证Shopify Webhook?
在Django/DRF中验证Shopify Webhook
Shopify Webhook的验证核心是通过共享密钥对请求体进行HMAC-SHA256签名校验,以下是两种在Django/DRF中的实现方案:
方案一:自定义装饰器(适用于函数视图)
先编写一个验证装饰器,对请求的HMAC签名进行校验,通过后才会执行视图逻辑:
import hmac import base64 from django.http import HttpResponseForbidden from django.conf import settings def verify_shopify_webhook(view_func): def wrapper(request, *args, **kwargs): # 获取请求头中的HMAC签名 shopify_hmac = request.META.get('HTTP_X_SHOPIFY_HMAC_SHA256') if not shopify_hmac: return HttpResponseForbidden('Missing HMAC header') # 获取原始请求体(必须用未解析的字节数据) raw_body = request.body # 用Shopify Webhook密钥生成签名 digest = hmac.new( settings.SHOPIFY_WEBHOOK_SECRET.encode('utf-8'), raw_body, digestmod='sha256' ).digest() computed_hmac = base64.b64encode(digest).decode('utf-8') # 安全对比签名(防止时序攻击) if not hmac.compare_digest(computed_hmac, shopify_hmac): return HttpResponseForbidden('Invalid HMAC signature') return view_func(request, *args, **kwargs) return wrapper
在函数视图中使用这个装饰器:
from django.http import HttpResponse @verify_shopify_webhook def shopify_order_webhook(request): # 这里处理Webhook的业务逻辑,比如解析request.body或request.data return HttpResponse('OK')
方案二:自定义DRF权限类(适用于类视图/视图集)
如果使用DRF的类视图或视图集,可以编写一个自定义权限类,统一处理Webhook验证:
import hmac import base64 from rest_framework.permissions import BasePermission from django.conf import settings class ShopifyWebhookPermission(BasePermission): def has_permission(self, request, view): shopify_hmac = request.META.get('HTTP_X_SHOPIFY_HMAC_SHA256') if not shopify_hmac: return False raw_body = request.body digest = hmac.new( settings.SHOPIFY_WEBHOOK_SECRET.encode('utf-8'), raw_body, digestmod='sha256' ).digest() computed_hmac = base64.b64encode(digest).decode('utf-8') return hmac.compare_digest(computed_hmac, shopify_hmac)
在DRF类视图中配置权限:
from rest_framework.views import APIView from rest_framework.response import Response class ShopifyProductWebhook(APIView): permission_classes = [ShopifyWebhookPermission] def post(self, request): # 处理Webhook逻辑,比如保存数据到数据库 return Response({'status': 'success'})
关键注意事项
settings.SHOPIFY_WEBHOOK_SECRET是你在Shopify后台创建Webhook时生成的共享密钥,务必存储在环境变量或安全的配置中,不要硬编码。- 必须使用
hmac.compare_digest对比签名,不能直接用==,避免时序攻击风险。 - DRF的
request.body始终是原始的字节数据,即使使用了JSON解析器也不会影响签名校验,因为DRF是先读取原始数据再解析为request.data的。
内容的提问来源于stack exchange,提问作者JPG
相关产品推荐
相关产品推荐

