php - PHP 中的 Azure REST Api 给出 "Given value does not match HMAC header structure"

标签 php azure hmac azure-rest-api

我正在尝试连接到 Azure 通信 API 以使用 REST 终结点发送 SMS 消息。

API 说明的链接位于:https://learn.microsoft.com/en-us/azure/azure-app-configuration/rest-api-authentication-hmac

我的PHP代码如下:

    public static function send(array $phoneNumbers, string $message)
    {
        $body = json_encode([
            'from' => config("azure.sms_phone_number"),
            'message' => $message,
            'smsRecipients' => array_map(fn ($num) => ['to' => $num], $phoneNumbers)
        ]);

        $endpoint = parse_url(config("azure.sms_endpoint"));

        $headers = [
            'Date' => gmdate("D, d M y H:i:s T"),
            'host' => $endpoint['host'],
            'x-ms-content-sha256' => base64_encode(hash('sha256', $body, true)),
            'Content-Type' => 'application/json',
            'Accept' => '*/*'
        ];

        $stringToSign = utf8_encode("POST\n" . $endpoint['path'] . "?" . $endpoint['query'] . "\n" . implode(";", array_values($headers)));

        $headers['Authorization'] = implode("&", [
            "HMAC-SHA256 Credential=" . config("azure.sms_key_id"),
            "SignedHeaders=" . implode(";", array_keys($headers)),
            'Signature=' . base64_encode(hash_hmac('sha256', $stringToSign, base64_decode(config("azure.sms_key")), true))
        ]);

        $client = new Client();

        $client->post(config("azure.sms_endpoint"), [
            'headers' => $headers,
            'body' => $body,
            'debug' => true
        ]);
    }

下面是一些变量

$body = '{"from":"+1844295xxx","message":"hi","smsRecipients":[{"to":"2019160xxx"}]};';

$stringToSign = 'POST
/sms?api-version=2021-03-07
Mon, 14 Mar 22 17:09:17 GMT;testxxxxxx.communication.azure.com;UXoK8141pppkVedAkc+eSQBqKOWciyoiq+AG/xxxxxx=;application/json;*/*;';

$headers = 
(
    [Date] => Mon, 14 Mar 22 17:09:17 GMT
    [host] => testxxxxx.communication.azure.com
    [x-ms-content-sha256] => UXoK8141pppkVedAkc+eSQBqKOWciyoiq+AG/xxxxxx=
    [Content-Type] => application/json
    [Accept] => */*
    [Authorization] => HMAC-SHA256 Credential=primaryKey&SignedHeaders=Date;host;x-ms-content-sha256;Content-Type;Accept&Signature=R8M7+fODzXaxXHbdcV5CHXiEq5R/7Fvd9VGYxxxxxxx=
)

我得到的结果是这样的:

Client error: `POST https://test.communication.azure.com/sms?api-version=2021-03-07` resulted in a `401 Unauthorized` response:
{"error":{"code":"Denied","message":"Given value does not match HMAC header structure."}}

访问 key 和名称来自此命令:

PS C:\Users\manko> az communication list-key --name scotttestingsms --resource-group smsresourcegroup
{
  "primaryConnectionString": "endpoint=https://scotttestingsms.communication.azure.com/;accesskey=E7lrdL/yyg/snSO++rbaZMEUF/bC5/0R9XBVGcFclt3fEN/MpWRb5kHB9t59NLtek9xsUYXHyAXxxxxxxx==",
  "primaryKey": "E7lrdL/yyg/snSO++rbaZMEUF/bC5/0R9XBVGcFclt3fEN/MpWRb5kHB9t59NLtek9xsUYXHyAXxxxxxx==",
  "secondaryConnectionString": "endpoint=https://scotttestingsms.communication.azure.com/;accesskey=IIK094eGVfkNG0uFii/32j+HVsEHJ4/QUOx06TVsqwLub7A/cv1AKKnkkZQbKiJKMn/KRx9o1biWQ5txxxxxx==",
  "secondaryKey": "IIK094eGVfkNG0uFii/32j+HVsEHJ4/QUOx06TVsqwLub7A/cv1AKKnkkZQbKiJKMn/KRx9o1biWQ5txxxxxx=="
}

最佳答案

花了相当长的时间进行试验和错误,但下面的代码可以工作。请参阅 https://learn.microsoft.com/en-us/azure/communication-services/tutorials/hmac-header-tutorial 了解更多信息。

use GuzzleHttp\Client;

    public static function send(array $phoneNumbers, string $message)
    {
        $body = [
            'from' => config("azure.sms_phone_number"),
            'message' => $message,
            'smsRecipients' => array_map(fn ($num) => ['to' => $num], $phoneNumbers)
        ];

        $endpoint = parse_url(config("azure.sms_endpoint"));

        $headers = [
            'Date' => gmdate("D, d M Y H:i:s T"),
            'host' => $endpoint['host'],
            'x-ms-content-sha256' => base64_encode(hash('sha256', json_encode($body), true)),
        ];

        $stringToSign = utf8_encode(implode("\n", [
            "POST",
            $endpoint['path'] . "?" . $endpoint['query'],
            implode(";", array_values($headers))
        ]));

        $headers['Authorization'] = implode("&", [
            "HMAC-SHA256 SignedHeaders=" . implode(";", array_keys($headers)),
            'Signature=' . base64_encode(hash_hmac('sha256', $stringToSign, base64_decode(config("azure.sms_key")), true))
        ]);

        $client = new Client();  // <-- this is guzzle

        $response = $client->post(config("azure.sms_endpoint"), [
            'headers' => $headers,
            'json' => $body
        ]);

    }

您只需要三条数据。

  1. config("azure.sms_phone_number") 是原始电话号码。它必须是 E.164 格式,例如“+12024561414”
  2. config("azure.sms_endpoint") 是完整端点,例如“https://test.communication.azure.com/sms?api-version=2021-03-07”
  3. config("azure.sms_key") 是从 Azure 门户以 Base64 格式复制的应用程序 key ,例如“E7lrdL/yyg/snSO++rbaZMEUF/d1G/0R9XBVGch0tq3xxxxxxxxxxxx==”

关于php - PHP 中的 Azure REST Api 给出 "Given value does not match HMAC header structure",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71439439/

相关文章:

javascript - 如何根据一些数据动态添加 Font Awesome 图标

php - MySQL 注册案例

c# - Application Insights 中的 Azure 函数 TimerTrigger 结果代码始终成功

大型数组的 PHP 内存错误

php - 这个PHP登录功能安全吗?

azure - 内部版本 : Cannot use JSX unless the '--jsx' flag is provided

azure - DocumentDB 的空间索引

javascript - 为什么我的 crypto.createHmac() 会为相同的输入生成不同的 HMAC?

javascript - Coinbase.com API + Node.js 中的 secret HMAC 身份验证

java - 渐进式 HMACSHA256 的 C# 等效项是什么?