You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 21:55:20