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

Laravel中Xero Webhooks接收验证失败问题求助

Xero Webhook签名验证失败的解决方案

核心问题出在Webhook密钥的处理方式以及哈希函数的返回格式设置上,以下是具体修正方案:

错误原因拆解

  • 你定义的WEBHOOKKEY是Base64编码后的字符串,Xero要求使用解码后的原始字节作为HMAC密钥,直接用Base64字符串计算会导致哈希结果完全错误。
  • hash_hmac函数默认返回十六进制字符串,直接对其做Base64编码会得到比签名更长的结果;必须让它返回原始二进制数据,再进行Base64编码才能匹配Xero的签名格式。

修正后的代码

<?php

namespace App\Http\Controllers\Xero;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class ContactsController extends Controller
{
    const WEBHOOKKEY = '+3mCdl4IykKfH+Y9CZTy5TpvqB4ir3RsdwJmdpKXnR9xCTIQrKCQAKYii5IioTaujGYojiKfV7IUu7cywypuSg==';
    
    public function index(Request $request) 
    {
        $signature = $request->header('x-xero-signature');
        // 1. 解码Base64格式的Webhook密钥为原始字节
        $decodedKey = base64_decode(self::WEBHOOKKEY);
        // 2. 使用原始密钥计算HMAC-SHA256,第三个参数设为true返回二进制数据
        $hmacBinary = hash_hmac('sha256', $request->getContent(), $decodedKey, true);
        // 3. 对二进制结果做Base64编码,得到与Xero签名格式一致的字符串
        $hash = base64_encode($hmacBinary);

        if ($signature === $hash) {
            return response('OK', 200);
        }

        return response('Unauthorized', 401);
    }
}

额外验证提示

  • 确保请求体是原始未修改的:Laravel的$request->getContent()会返回原始请求负载,但要避免在前置中间件中修改请求内容(比如解析JSON后重新编码,可能改变空格、换行符等格式,导致哈希不匹配)。
  • 测试时直接使用Xero发送的Intent to Receive请求,不要自行构造,避免请求体格式差异。

内容的提问来源于stack exchange,提问作者Lochinvar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:22:46