Shopify触发Python版Azure Function时Webhook验证失败求助
Shopify Webhook验证失败的排查与修复
问题根源
你的验证逻辑核心错误在于使用了解析后再序列化的JSON数据计算HMAC,而Shopify的Webhook签名是基于原始请求体的字节流生成的。req.get_json()会将请求体解析为Python字典,再用json.dumps()序列化时,可能会改变原始JSON的格式(比如空格、键的顺序、转义字符处理),导致计算出的HMAC和Shopify发送的签名不匹配。
修复步骤
修改verify函数,直接使用原始请求体字节计算HMAC,而不是解析后的JSON对象:
import azure.functions as func import logging import hmac import hashlib import base64 app = func.FunctionApp() @app.function_name(name="webhook-trigger") @app.route(route="webhook", auth_level=func.AuthLevel.ANONYMOUS) def webhook_process(req: func.HttpRequest) -> func.HttpResponse: logging.info('Python HTTP trigger function is processing a request.') verified = verify(req) logging.info("Webhook verified: {}".format(verified)) return func.HttpResponse( "This HTTP triggered function executed successfully.", status_code=200 ) def verify(req: func.HttpRequest) -> bool: CLIENT_SECRET = 'xxxxx' # 替换为你的Shopify客户端密钥 shopify_hmac = req.headers.get('X-Shopify-Hmac-Sha256') if not shopify_hmac: logging.warning("Missing X-Shopify-Hmac-Sha256 header") return False # 获取原始请求体字节,不要解析成JSON raw_data = req.get_body() if not raw_data: logging.warning("Empty request body") return False # 计算HMAC digest = hmac.new(CLIENT_SECRET.encode('utf-8'), raw_data, digestmod=hashlib.sha256).digest() computed_hmac = base64.b64encode(digest) logging.info("computed_hmac: {}".format(computed_hmac)) logging.info("shopify_hmac encoded: {}".format(shopify_hmac.encode('utf-8'))) # 用compare_digest做安全的比较 verified = hmac.compare_digest(computed_hmac, shopify_hmac.encode('utf-8')) return verified
额外注意事项
- 不要修改原始请求体:确保没有对原始字节流做任何修改(比如解码后再编码),保持和Shopify发送的完全一致。
- 密钥正确性:确认
CLIENT_SECRET是Shopify后台生成的正确密钥,不是API密钥或其他凭证。 - header大小写兼容:Azure Function的请求header可能存在小写情况,可改为
req.headers.get('X-Shopify-Hmac-Sha256', req.headers.get('x-shopify-hmac-sha256'))避免遗漏。
内容的提问来源于stack exchange,提问作者Zin Yosrim
相关产品推荐
相关产品推荐

