亚马逊 MWS |安息夏普 |我们计算出的请求签名与您提供的签名不匹配

Amazon MWS | RestSharp | The request signature we calculated does not match the signature you provided

我写了下面的 method 来获取 Amazon 的所有订单。我正在使用 RestSharp 库与 API 进行通信。每次我执行 request 我都会收到以下错误:

<?xml version="1.0"?>
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01">
  <Error>
    <Type>Sender</Type>
    <Code>SignatureDoesNotMatch</Code>
    <Message>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.</Message>
  </Error>
  <RequestID>9f03f5b0-e4e4-4766-a554-00ff970b6b8c</RequestID>
</ErrorResponse>

这很奇怪,因为在 Amazon Scratchpad (https://mws.amazonservices.de/scratchpad/index.html) 上它正在工作,我也得到相同的 signature (当我使用在 Scratchpad 上计算的时间戳时)我的 c# 应用程序。

C#Class

public async void FetchOrders()
{
    RestClient client = new RestClient("https://mws.amazonservices.de");
    client.DefaultParameters.Clear();
    client.ClearHandlers();

    Dictionary<string, string> parameters = new Dictionary<string, string>();
    parameters.Add("AWSAccessKeyId", "xxxxxxxxxx");
    parameters.Add("Action", "ListOrders");
    parameters.Add("CreatedAfter", "2018-01-01T11:34:00Z");
    parameters.Add("MarketplaceId.Id.1", "A1PA6795UKMFR9");
    parameters.Add("SellerId", "xxxxxxxxx");
    parameters.Add("SignatureVersion", "2");
    parameters.Add("Timestamp", DateTime.UtcNow.ToString("s") + "Z");
    parameters.Add("Version", "2013-09-01");

    RestRequest request = new RestRequest("Orders/2013-09-01/", Method.POST);

    string signature = AmzLibrary.SignParameters(parameters, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    request.AddParameter("Signature", signature);

    foreach (KeyValuePair<string, string> keyValuePair in parameters)
    {
        request.AddParameter(keyValuePair.Key, keyValuePair.Value);
    }

    IRestResponse result = await client.ExecuteTaskAsync(request);
}



public static class AmzLibrary
{
    public static string GetParametersAsString(IDictionary<String, String> parameters)
    {
        StringBuilder data = new StringBuilder();
        foreach (String key in (IEnumerable<String>)parameters.Keys)
        {
            String value = parameters[key];
            if (value != null)
            {
                data.Append(key);
                data.Append('=');
                data.Append(UrlEncode(value, false));
                data.Append('&');
            }
        }
        String result = data.ToString();
        return result.Remove(result.Length - 1);
    }

    public static String SignParameters(IDictionary<String, String> parameters, String key)
    {
        String signatureVersion = parameters["SignatureVersion"];

        KeyedHashAlgorithm algorithm = new HMACSHA1();

        String stringToSign = null;
        if ("2".Equals(signatureVersion))
        {
            String signatureMethod = "HmacSHA256";
            algorithm = KeyedHashAlgorithm.Create(signatureMethod.ToUpper());
            parameters.Add("SignatureMethod", signatureMethod);
            stringToSign = CalculateStringToSignV2(parameters);
        }
        else
        {
            throw new Exception("Invalid Signature Version specified");
        }

        return Sign(stringToSign, key, algorithm);
    }

    private static String CalculateStringToSignV2(IDictionary<String, String> parameters)
    {
        StringBuilder data = new StringBuilder();
        IDictionary<String, String> sorted =
              new SortedDictionary<String, String>(parameters, StringComparer.Ordinal);
        data.Append("POST");
        data.Append("\n");
        Uri endpoint = new Uri("https://mws.amazonservices.de/Orders/2013-09-01");

        data.Append(endpoint.Host);
        if (endpoint.Port != 443 && endpoint.Port != 80)
        {
            data.Append(":")
                .Append(endpoint.Port);
        }
        data.Append("\n");
        String uri = endpoint.AbsolutePath;
        if (uri == null || uri.Length == 0)
        {
            uri = "/";
        }
        data.Append(UrlEncode(uri, true));
        data.Append("\n");
        foreach (KeyValuePair<String, String> pair in sorted)
        {
            if (pair.Value != null)
            {
                data.Append(UrlEncode(pair.Key, false));
                data.Append("=");
                data.Append(UrlEncode(pair.Value, false));
                data.Append("&");
            }

        }

        String result = data.ToString();
        return result.Remove(result.Length - 1);
    }

    private static String UrlEncode(String data, bool path)
    {
        StringBuilder encoded = new StringBuilder();
        String unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~" + (path ? "/" : "");

        foreach (char symbol in System.Text.Encoding.UTF8.GetBytes(data))
        {
            if (unreservedChars.IndexOf(symbol) != -1)
            {
                encoded.Append(symbol);
            }
            else
            {
                encoded.Append("%" + String.Format("{0:X2}", (int)symbol));
            }
        }

        return encoded.ToString();

    }

    private static String Sign(String data, String key, KeyedHashAlgorithm algorithm)
    {
        Encoding encoding = new UTF8Encoding();
        algorithm.Key = encoding.GetBytes(key);
        return Convert.ToBase64String(algorithm.ComputeHash(
            encoding.GetBytes(data.ToCharArray())));
    }
}

问题出在 Request 末尾的 "/"。删除它,一切正常。

错误

RestRequest request = new RestRequest("Orders/2013-09-01/", Method.POST);

RestRequest request = new RestRequest("Orders/2013-09-01", Method.POST);