Я использую Orderhive API (https://orderhive.docs.apiary.io/#reference / product / product-catalog ), который использует аутентификацию подписи AWS4. Мне нужно получить все продукты с этой конечной точкой: https://api.orderhive.com/product/listing/flat?size=100&page=1, но всегда получаю ошибку The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been\n'POST\n/product/listing/flat\npage=1&size=500
Ниже приведена текущая реализация
var endpoint = "https://api.orderhive.com/product/listing/flat?size=100&page=1";
var uri = new Uri(endpointUri);
var helpers = new HttpHelpers();
var result = helpers.InvokeHttpRequest(uri, "POST", PopulateHeader(endpoint, content, ""), content);
private Dictionary<string, string> PopulateHeader(string endpointUri, string content, string next_token)
{
// precompute hash of the body content
var contentHash = AWS4SignerBase.CanonicalRequestHashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(content));
var contentHashString = AWS4SignerBase.ToHexString(contentHash, true);
var headers = new Dictionary<string, string>
{
{AWS4SignerBase.X_Amz_Content_SHA256, contentHashString},
{"content-length", Encoding.UTF8.GetByteCount(content).ToString()},
{"content-type", "application/json"},
{"id_token", _credentails.id_token},
{"X-Amz-Security-Token", _credentails.session_token}
};
var uri = new Uri(endpointUri);
var signer = new AWS4SignerForAuthorizationHeader
{
EndpointUri = uri,
HttpMethod = "POST",
Service = awsServiceName,
Region = awsRegion
};
string queryString = new System.Uri(endpointUri).Query;
var authorization = signer.ComputeSignature(headers,
queryString,
contentHashString,
_credentails.access_key_id,
_credentails.secret_key);
// express authorization for this as a header
headers.Add("Authorization", authorization);
return headers;
}
public string ComputeSignature(IDictionary<string, string> headers,
string queryParameters,
string bodyHash,
string awsAccessKey,
string awsSecretKey)
{
// first get the date and time for the subsequent request, and convert to ISO 8601 format
// for use in signature generation
var requestDateTime = DateTime.UtcNow;
var dateTimeStamp = requestDateTime.ToString(ISO8601BasicFormat, CultureInfo.InvariantCulture);
// update the headers with required 'x-amz-date' and 'host' values
headers.Add(X_Amz_Date, dateTimeStamp);
var hostHeader = EndpointUri.Host;
if (!EndpointUri.IsDefaultPort)
hostHeader += ":" + EndpointUri.Port;
headers.Add("Host", hostHeader);
// canonicalize the headers; we need the set of header names as well as the
// names and values to go into the signature process
var canonicalizedHeaderNames = CanonicalizeHeaderNames(headers);
var canonicalizedHeaders = CanonicalizeHeaders(headers);
// if any query string parameters have been supplied, canonicalize them
// (note this sample assumes any required url encoding has been done already)
var canonicalizedQueryParameters = string.Empty;
if (!string.IsNullOrEmpty(queryParameters))
{
var paramDictionary = queryParameters.Split('&').Select(p => p.Split('='))
.ToDictionary(nameval => nameval[0],
nameval => nameval.Length > 1
? nameval[1] : "");
var sb = new StringBuilder();
var paramKeys = new List<string>(paramDictionary.Keys);
paramKeys.Sort(StringComparer.Ordinal);
foreach (var p in paramKeys)
{
if (sb.Length > 0)
sb.Append("&");
sb.AppendFormat("{0}={1}", p, paramDictionary[p]);
}
canonicalizedQueryParameters = sb.ToString();
}
// canonicalize the various components of the request
var canonicalRequest = CanonicalizeRequest(EndpointUri,
HttpMethod,
canonicalizedQueryParameters,
canonicalizedHeaderNames,
canonicalizedHeaders,
bodyHash);
Console.WriteLine("\nCanonicalRequest:\n{0}", canonicalRequest);
// generate a hash of the canonical request, to go into signature computation
var canonicalRequestHashBytes
= CanonicalRequestHashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest));
// construct the string to be signed
var stringToSign = new StringBuilder();
var dateStamp = requestDateTime.ToString(DateStringFormat, CultureInfo.InvariantCulture);
var scope = string.Format("{0}/{1}/{2}/{3}",
dateStamp,
Region,
Service,
TERMINATOR);
stringToSign.AppendFormat("{0}-{1}\n{2}\n{3}\n", SCHEME, ALGORITHM, dateTimeStamp, scope);
stringToSign.Append(ToHexString(canonicalRequestHashBytes, true));
Console.WriteLine("\nStringToSign:\n{0}", stringToSign);
// compute the signing key
var kha = KeyedHashAlgorithm.Create(HMACSHA256);
kha.Key = DeriveSigningKey(HMACSHA256, awsSecretKey, Region, dateStamp, Service);
// compute the AWS4 signature and return it
var signature = kha.ComputeHash(Encoding.UTF8.GetBytes(stringToSign.ToString()));
var signatureString = ToHexString(signature, true);
Console.WriteLine("\nSignature:\n{0}", signatureString);
var authString = new StringBuilder();
authString.AppendFormat("{0}-{1} ", SCHEME, ALGORITHM);
authString.AppendFormat("Credential={0}/{1}, ", awsAccessKey, scope);
authString.AppendFormat("SignedHeaders={0}, ", canonicalizedHeaderNames);
authString.AppendFormat("Signature={0}", signatureString);
var authorization = authString.ToString();
Console.WriteLine("\nAuthorization:\n{0}", authorization);
return authorization;
}