我正在尝试签署 AWS API 请求,然后使用 cURL。
目的是向服务提供商的 API 提交跟踪号,并使用响应。
我完全是 AWS API 的菜鸟,经过多次测试后找不到我的错。
我尝试了很多方法,但都导致{"message":"Forbidden"}.
{"message":"Forbidden"}
这是我当前的脚本:
<?php $accessKeyId = "AKIA55D**********"; $secretAccessKey = "NQ0xcl**********"; $method ='GET'; $uri = '/tracking/shipments'; $secretKey = $secretAccessKey; $access_key = $accessKeyId; $region = 'af-south-1'; $service = 'execute-api'; $host = "https://api.shiplogic.com"; $alg = 'sha256'; $date = new DateTime('Africa/Johannesburg'); $dd = $date->format( 'Ymd\THis\Z' ); $amzdate2 = new DateTime( 'Africa/Johannesburg' ); $amzdate2 = $amzdate2->format( 'Ymd' ); $amzdate = $dd; $algorithm = 'AWS4-HMAC-SHA256'; $canonical_uri = $uri; $canonical_querystring = ''; $canonical_headers = "host:".$host."\n"."x-amz-date:".$amzdate."\n"; $signed_headers = 'host;x-amz-date'; $canonical_request = "".$method."\n".$canonical_uri."\n".$canonical_querystring."\n".$canonical_headers."\n".$signed_headers; $credential_scope = $amzdate2 . '/' . $region . '/' . $service . '/' . 'aws4_request'; $string_to_sign = "".$algorithm."\n".$amzdate ."\n".$credential_scope."\n".hash('sha256', $canonical_request).""; //string_to_sign is the answer..hash('sha256', $canonical_request)// $kSecret = 'AWS4' . $secretKey; $kDate = hash_hmac( $alg, $amzdate2, $kSecret, true ); $kRegion = hash_hmac( $alg, $region, $kDate, true ); $kService = hash_hmac( $alg, $service, $kRegion, true ); $kSigning = hash_hmac( $alg, 'aws4_request', $kService, true ); $signature = hash_hmac( $alg, $string_to_sign, $kSigning ); $authorization_header = $algorithm . ' ' . 'Credential=' . $access_key . '/' . $credential_scope . ', ' . 'SignedHeaders=' . $signed_headers . ', ' . 'Signature=' . $signature; $headers = [ 'content-type'=>'application/json', 'x-amz-date'=>$amzdate, 'Authorization'=>$authorization_header]; $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => 'https://api.shiplogic.com/tracking/shipments?tracking_reference=M3RPH', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => array( 'X-Amz-Date: '.$amzdate.'', 'Authorization: ' . $authorization_header . '' ), )); $response = curl_exec($curl); curl_close($curl); echo $response;
我收到的回复是{"message":"Forbidden"}
我究竟做错了什么?
如评论中已经指出的那样,安装亚马逊的 PHP SDK 。
composer require aws/aws-sdk-php
您尝试调用的 API 文档有1 个 PHP 代码示例,它使用该 SDK。您需要做的就是插入您的凭据。
use Aws\Credentials\Credentials; use Aws\Signature\SignatureV4; use Psr\Http\Message\RequestInterface; function sign( RequestInterface $request, string $accessKeyId, string $secretAccessKey ): RequestInterface { $signature = new SignatureV4('execute-api', 'af-south-1'); $credentials = new Credentials($accessKeyId, $secretAccessKey); return $signature->signRequest($request, $credentials); }
您可以看到输入$request和返回值都是相同的RequestInterface类型。因此,它为您提供了一个具有适当签名的修改请求对象(如果您的密钥和参数有效)。
$request
RequestInterface
如果你正在使用curl,你可能还没有这个请求对象。Amazon 的 API 使用PSR-7 标准请求接口,大多数框架如果有请求对象就会实现这一点。
curl
如果你手头没有请求对象,你可以使用Guzzle 的实现。所需的包已经安装为Amazon 的 SDK 的依赖项。您可以从 Github 永久链接安装两个突出显示的软件包。
$request = new GuzzleHttp\Psr7\Request( 'GET', 'https://api.shiplogic.com/tracking/shipments', [ // Maybe you still need headers. ] ); $signed_request = sign($request); $client = new \GuzzleHttp\Client(); $response = $client->send($signed_request);
正如评论中提到的,应尽可能避免创建自己的安全组件实现。重写代码以使用此请求对象要容易得多,尤其是对于将来的维护。
另请记住,您的凭据可能只是无效,或者无法访问您请求的资源。乍一看,您的大部分实现似乎都遵循了签名协议的预期(尽管您只需要一个小错误并且它不会起作用),所以如果您确定您检查了所有内容,它可能就这么简单。