使用:Delphi 10.2.3 Tokyo IPWorks SSL 和 IPWorks Encrypt 组件
我正在尝试使用 Delphi 的亚马逊 MWS API 来获取订单列表,但未能成功向亚马逊 MWS 发出请求。根据客户的要求,我必须使用 IPWorks 组件。API 的响应表明签名不正确:
发件人
SignatureDoesNotMatch
我们计算的请求签名与您提供的签名不匹配。检查您的 AWS 秘密访问密钥和签名方法。有关详细信息,请参阅服务文档。
显然,这个问题与计算签名、将其编码为 Base64 或请求本身有问题有关。我认为它对 Base64 的编码对我不起作用。也许与 Delphi Unicode 和 UTF-8 编码有关。
我花了一整天的时间试图弄清楚这一点并且被卡住了,所以我把它贴在这里。我希望有人能帮帮忙。下面是我的代码:
在表单上,我有 2 个组件:TipwHTTP 和 TipcHash
object HTTPS: TipwHTTP
FollowRedirects = frAlways
SSLCertStore = 'MY'
OnTransfer = HTTPSTransfer
end
object HashMaker: TipcHash
Algorithm = haHMACSHA256
EncodeHash = True
end
function GetISO8601DateTime_URLEncodedStr(const ADateTime: TDateTime): String;
var
d: String;
l: Integer;
begin
d := DateToISO8601(TTimeZone.Local.ToUniversalTime(ADateTime), True);
l := Length(d);
d := Copy(d, 1, l - 5) + 'Z'; // remove the milliseconds part
Result := TNetEncoding.URL.Encode(d);
end;
const
DOMAIN_NAME = 'https://mws.amazonservices.com/Orders/2013-09-01';
var
sl: TStringList;
param, signature, aurl: String;
begin
sl := TStringList.Create;
try
sl.Add('AWSAccessKeyId=' + edtAwsAccessKey.Text); { Index: 0 }
sl.Add('&Action=ListOrders'); { Index: 1 }
sl.Add('&CreatedAfter=' + GetISO8601DateTime_URLEncodedStr(dtpOrdersCreatedFrom.Date)); { Index: 2 }
sl.Add('&MWSAuthToken=' + edtMarketplaceID.Text); { Index: 3 }
sl.Add('&MarketplaceId.Id.1=' + edtMarketplaceID.Text); { Index: 4 }
sl.Add('&SellerId=' + edtSellerID.Text); { Index: 5 }
sl.Add('&SignatureMethod=HmacSHA256'); { Index: 6 } // <---- Insert Signature here
sl.Add('&SignatureVersion=2'); { Index: 7 }
sl.Add('&Timestamp=' + GetISO8601DateTime_URLEncodedStr(Now)); { Index: 8 }
sl.Add('&Version=2013-09-01'); { Index: 9 }
param := StringReplace(sl.Text, #13#10, '', [rfReplaceAll]);
HashMaker.Key := edtSecretKey.Text;
HashMaker.Algorithm := haHMACSHA256;
HashMaker.InputMessage := 'POST\n' + 'mws.amazonservices.com\n' + '/Orders/2013-09-01\n' + param;
HashMaker.ComputeHash;
signature := HashMaker.HashValue;
SetStatus('Signature1: ' + signature);
signature := TNetEncoding.Base64.Encode(TEncoding.UTF8.GetString(BytesOf(signature)));
signature := TNetEncoding.URL.Encode(signature);
SetStatus('Signature2: ' + signature);
sl.Insert(6, '&Signature=' + signature);
param := StringReplace(sl.Text, #13#10, '', [rfReplaceAll]);
SetStatus('param: ' + param);
finally
sl.Free;
end;
with HTTPS do
begin
ContentType := 'application/x-www-form-urlencoded; charset=UTF-8';
Accept := 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8';
Timeout := 0;
aurl := DOMAIN_NAME + '?' + param;
Post(aurl);
end;
end;
如果有人可以帮助我解决这个问题,我将不胜感激。
-史蒂夫