Delphi — расчет подписи Amazon MWS
Использование: компоненты Delphi 10.2.3 Tokyo IPWorks SSL и IPWorks Encrypt
Я пытаюсь использовать API Amazon MWS от Delphi для получения списка заказов, но не могу отправить запрос в Amazon MWS. Я обязательно использую компоненты IPWorks, как того требует мой клиент. Ответ от API говорит, что подпись неверна:
Отправитель
Рассчитанная нами подпись запроса не соответствует предоставленной вами подписи. Проверьте свой секретный ключ доступа 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;
Я был бы очень признателен, если бы кто-нибудь помог мне решить эту проблему.
-Стив