0

Amazon Selling Partner API Token API を呼び出して RDT トークンを取得しようとしています。Orders API への GET リクエストを成功させる作業中のプログラムがありますが、Orders API への REST リクエストにはヘッダーと URL パラメーターのみが含まれています。トークン API リクエストには、制限付きリソースのリストが保存される HTTP 本文も (追加で) 含まれます。

Amazonは次のように返信します

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.

The Canonical String for this request should have been
'GET
 /tokens/2021-03-01/restrictedDataToken
 ...
 host;x-amz-access-token;x-amz-date\n
 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
 ...
 The String-to-Sign should have been
 ...
 ...

私のトークンAPIプログラムで。e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855私の問題の鍵です。これは、ヘッダー、URL パラメーター、および本文コンテンツの初期セットからのコンピューターであるハッシュ化されたペイロード (次のリンクの図を参照) です。私のプログラムによって計算されるハッシュ化されたペイロードは、Amazon が本文なしのリクエストに対して返し、受け入れるものと同じです。しかし、Amazon と私のプログラムの Hashed ペイロードは、本文のあるリクエストでは異なります。したがって、私のプログラムは Amazon とは異なる方法で本体を追加およびハッシュすると結論付けました。それが、Amazon がトークン API リクエストを受け入れない理由です。

AWS - 正規のリクエストとは実際には何ですか? Amazonサービスへの完全なリクエストがどのように計算されるか、素晴らしい図があります。

C# コードを使用して HTTP 本文を計算して追加しています。

        Model.RestrictedResource restrictedResource = new Model.RestrictedResource(
            Model.RestrictedResource.MethodEnum.GET,
            "/orders/v0/orders",
            new List<String> {"buyerInfo", "shippingAddress"});
        List<Model.RestrictedResource> restrictedResources = new List<Model.RestrictedResource>();
            restrictedResources.Add(restrictedResource);
            Model.CreateRestrictedDataTokenRequest request = new Model.CreateRestrictedDataTokenRequest("", restrictedResources);

            IRestRequest restRequest = new RestRequest(rdt_resource, Method.GET);
            restRequest.AddParameter("MarketplaceIds", marketplace_id, ParameterType.QueryString);
            restRequest.AddJsonBody(Serialize(request));
            //restRequest.AddBody(Serialize(request)); //Alternative solution, the same Amazon error about differing hashed payload values

ハッシュ化された CanonicalRequest 文字列を計算するコードは次のとおりです。

   public IRestRequest Sign(IRestRequest request, string host)
    {
        DateTime signingDate = AwsSignerHelper.InitializeHeaders(request, host);
        string signedHeaders = AwsSignerHelper.ExtractSignedHeaders(request);

        string hashedCanonicalRequest = CreateCanonicalRequest(request, signedHeaders);

        string stringToSign = AwsSignerHelper.BuildStringToSign(signingDate,
                                                                hashedCanonicalRequest,
                                                                awsCredentials.Region);

        string signature = AwsSignerHelper.CalculateSignature(stringToSign,
                                                              signingDate,
                                                              awsCredentials.SecretKey,
                                                              awsCredentials.Region);

        AwsSignerHelper.AddSignature(request,
                                     awsCredentials.AccessKeyId,
                                     signedHeaders,
                                     signature,
                                     awsCredentials.Region,
                                     signingDate);

        return request;
    }

    private string CreateCanonicalRequest(IRestRequest restRequest, string signedHeaders)
    {
        var canonicalizedRequest = new StringBuilder();
        //Request Method
        canonicalizedRequest.AppendFormat("{0}\n", restRequest.Method);

        //CanonicalURI
        canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalURIParameters(restRequest.Resource));

        //CanonicalQueryString
        canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalQueryString(restRequest));

        //CanonicalHeaders
        canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalHeaders(restRequest));

        //SignedHeaders
        canonicalizedRequest.AppendFormat("{0}\n", signedHeaders);

        // Hash(digest) the payload in the body
        canonicalizedRequest.AppendFormat(AwsSignerHelper.HashRequestBody(restRequest));

        string canonicalRequest = canonicalizedRequest.ToString();

        //Create a digest(hash) of the canonical request
        return Utils.ToHex(Utils.Hash(canonicalRequest));
    }

    //This seems to be the key code - how body is extracted and hashed
    public virtual string HashRequestBody(IRestRequest request)
    {
        Parameter body = request.Parameters.FirstOrDefault(parameter => ParameterType.RequestBody.Equals(parameter.Type));
        string value = body != null ? body.Value.ToString() : string.Empty;
        return Utils.ToHex(Utils.Hash(value));
    }

だから、私は行方不明で、どこかでAmazonの慣習に従っていませんが、どこで. 何かがうまくいかない可能性があるポイントは複数ありrestRequest.AddJsonBody(Serialize(request));ます。2)HashRequestBody別の方法で実装する必要があるかもしれません (インターネットのどこかでコードを見つけたか、販売パートナーの API 仕様から Swagger によって生成されたコードを見つけました。

コードを微調整して、同じリクエスト (つまり、計算に使用され、計算の前に正規化されるリクエストの一部) に対して Amazon によって計算されたものとまったく同じハッシュ化されたペイロード (本文を含むリクエストの場合) を生成する方法ハッシュ化されたペイロードの)。

4

1 に答える 1

0

なんとか解決しました。問題のコードをこれらの変更と一緒に使用する必要があります。

TargetApplication を設定することが重要な場合があります。

 Model.CreateRestrictedDataTokenRequest request = new Model.CreateRestrictedDataTokenRequest("", restrictedResources);
 request.TargetApplication = "MyApplication";

また、シリアル化と本体の追加には、異なる型コードを使用する必要があります。そして、GET リクエストではなく POST リクエストを使用することが最終的に重要です。

IRestRequest restRequest = new RestRequest(rdt_resource, Method.POST);
            restRequest.AddParameter("MarketplaceIds", marketplace_id, ParameterType.QueryString);
            String postBody = SerializeBody(request);
            restRequest.AddParameter("application/json", postBody, ParameterType.RequestBody);
...
...
    public String SerializeBody(object obj)
    {
        try
        {
            return obj != null ? JsonConvert.SerializeObject(obj) : null;
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
    }

いいえ、次のエラー メッセージが表示されます。

Application does not have access to one or more requested data elements: [buyerInfo, shippingAddress]

しかし、技術的には、登録されたユーザーとアプリケーションが認識され、要求とその署名が適切に形成されているため、問題ありません。

于 2021-12-03T11:33:16.943 に答える