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

PHP生成AWS Signature Version 4签名对接Rekognition失败求助

问题分析与修复方案

你的代码存在几个关键错误,直接导致签名验证失败:

1. 请求URL带多余查询参数

Rekognition的application/x-amz-json-1.1接口不需要在URL中添加?Action=DetectFaces,操作已通过x-amz-target头指定。多余的查询参数会让规范请求的查询字符串部分与Postman生成的不一致,引发签名不匹配。

2. 请求体哈希计算错误

你用http_build_query($data)生成请求体哈希,但Rekognition要求的是JSON格式请求体的SHA256哈希,而非URL编码的键值对。这是核心错误,Postman会正确使用JSON字符串计算哈希,你的代码用了错误格式。

3. 规范请求的查询字符串处理

如果URL无查询参数,规范请求的第三部分应为空字符串,而非parse_url($url, PHP_URL_QUERY)返回的Action=DetectFaces。


修正后的代码

function sign_request($url, $data) { 
  $host = 'rekognition.eu-west-2.amazonaws.com';
  $access_key = '<<Acess_Key>>';
  $secret_key = '<<Secret_Key>>';
  $region = 'eu-west-2';
  $service = 'rekognition';

  $current = new DateTime('UTC');
  $current_date_time = $current->format('Ymd\THis\Z');
  $current_date = $current->format('Ymd');

  $signed_headers = [
    'content-type' => 'application/x-amz-json-1.1',
    'host' => $host,
    'x-amz-date' => $current_date_time,
    'x-amz-target' => 'RekognitionService.DetectFaces'
  ];
  $signed_headers_string = implode(';', array_keys($signed_headers));

  $canonical = [
    'POST',
    parse_url($url, PHP_URL_PATH),
    '', // 无查询参数,填空字符串
  ];
  
  foreach ($signed_headers as $header => $value) {
    $canonical[] = "$header:$value";
  }
  $canonical[] = ''; 
  $canonical[] = $signed_headers_string;
  // 关键修正:将数据转为标准JSON字符串后计算哈希
  $json_body = json_encode($data, JSON_UNESCAPED_SLASHES);
  $canonical[] = hash('sha256', $json_body);
  $canonical = implode("\n", $canonical);

  $credential_scope = [$current_date, $region, $service, 'aws4_request'];
  $key = array_reduce($credential_scope, fn ($key, $credential) => hash_hmac('sha256', $credential, $key, TRUE), 'AWS4' . $secret_key);
  $credential_scope = implode('/', $credential_scope);

  $string_to_sign = implode("\n", [
    'AWS4-HMAC-SHA256',
    $current_date_time,
    $credential_scope,
    hash('sha256', $canonical),
  ]);
  $signature = hash_hmac('sha256', $string_to_sign, $key);

  unset($signed_headers['host']);
  $signed_headers['Authorization'] = "AWS4-HMAC-SHA256 Credential=$access_key/$credential_scope, SignedHeaders=$signed_headers_string, Signature=$signature";
  
  return [
    'headers' => $signed_headers,
    'body' => $json_body
  ];
}

// 修正URL,移除多余查询参数
$requestUrl = 'https://rekognition.eu-west-2.amazonaws.com/';
$body = [
    "Attributes" => [
        "ALL"
    ],
    "Image" => [
        "Bytes" => "<<BASE64_of_Face_Image>>"
    ]
];

$result = sign_request($requestUrl, $body );
print_r($result['headers']);
// 发送请求时需使用$result['body']作为请求体

额外注意事项

  • 确保json_encode生成的JSON字符串与Postman发送的完全一致(JSON_UNESCAPED_SLASHES避免不必要转义)。
  • 验证x-amz-date格式严格符合YYYYMMDD'T'HHMMSS'Z',DateTime的UTC格式必须准确。
  • 签名头部的键名必须全小写,且在规范请求和SignedHeaders中完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:52:52