0

我必须按照本指南对 AWS API (SP-API) 执行签名请求:https ://github.com/amzn/ sell-partner-api-docs/blob/main/guides/en-US/use-案例指南/授权-api-用例指南/授权-api-用例指南-v1.md

我认为这个问题很容易适应对 AWS API 的类似请求。

下面是使用法拉第的日志请求,我得到“请求标头中缺少访问令牌”作为响应,但它实际上存在。我不知道我错过了什么。

要求

INFO -- request: GET https://sellingpartnerapi-eu.amazon.com/authorization/v1/authorizationCode?developerId=123456&mwsAuthToken=amzn.mws.XXXXX&sellingPartnerId=A27E0XXXXX
INFO -- request: host: "sellingpartnerapi-eu.amazon.com"

x-amz-date: "20210504T174042Z"
x-amz-security-token: "IQoJb3JpZ2luX2VjEHoaCWXXXX"
x-amz-content-sha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4XXXXXXXX"
authorization: "AWS4-HMAC-SHA256 Credential=ASIAXXXXXXXX/20210504/eu-west-1/execute-api/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=0f251c3abca8a73a764671418d64aXXXXXXXXX"
x-amz-access-token: "Atc|MQEBILWaaHz4CKGlzkSiMvrIqXXXXXXX"
user-agent: "App/1.0 (Language=Ruby)"
content-type: "application/json"

INFO -- response: Status 403
INFO -- response: date: "Tue, 04 May 2021 17:40:42 GMT"
content-type: "application/json"
content-length: "187"
connection: "keep-alive"
x-amzn-requestid: "2d51880c-6af3-4d93-9449-18e65b3e89e3"
x-amzn-errortype: "AccessDeniedException"
x-amz-apigw-id: "e0IMMGe-joEFsvA="

请求标头中缺少访问令牌。

首先,我请求一个无授权访问令牌(文档

    ACCESS_TOKEN_URL = 'https://api.amazon.com/auth/o2/token'.freeze
    AWS_SERVICE      = 'execute-api'.freeze

    def request_grantless_access_token
        body = {
          grant_type: 'client_credentials',
          client_id: ENV['SP_LWA_KEY'],
          client_secret: ENV['SP_LWA_SECRET'],
          scope: 'sellingpartnerapi::migration'
        }
        response = Faraday.post( ACCESS_TOKEN_URL, body, {
            'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
          }
        )
        JSON.parse(response.body)
    end

然后我签署并构建请求

def get_authorization_code()

        selling_partner_id = 'XXXXXXX'
        region             = 'eu'
        mws_auth_token     = 'amzn.mws.XXXXXX'
        endpoint           = "sellingpartnerapi-eu.amazon.com"

        aws_access_key_id     = ENV['SP_API_KEY']
        aws_secret_access_key = ENV['SP_API_SECRET']
        sts_iam_role_arn      = ENV['SP_IAM_ARN_ROLE']

        # REQUEST STS TOKEN
        aws_region = {
            'na' => 'us-east-1',
            'eu' => 'eu-west-1',
            'fe' => 'us-west-2'
        }[region.to_s] 

        # REQUEST STS TOKEN
        client = Aws::STS::Client.new(
            region: aws_region,
            access_key_id: aws_access_key_id,
            secret_access_key: aws_secret_access_key
        )

        # A “SessionToken” that is the value you must specify for the X-Amz-Security-Token Header
        sts_token       = client.assume_role(role_arn: sts_iam_role_arn, role_session_name: SecureRandom.uuid)

        # URL
        url          = "https://#{endpoint}/authorization/v1/authorizationCode?sellingPartnerId=#{selling_partner_id}&developerId=#{ENV['MWS_EU_DEVELOPER_ID']}&mwsAuthToken=#{mws_auth_token}"
        http_method  = 'GET'
        
        #SIGNED REQUEST
        request_config = {
            service: AWS_SERVICE,
            region: aws_region,
            endpoint: endpoint
        }
        
        # A credential provider is any object that responds to #credentials returning another object that responds to #access_key_id, #secret_access_key, and #session_token
        request_config[:credentials_provider] = sts_token
        
        # SIGNER: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Sigv4/Signer.html
        signer      = Aws::Sigv4::Signer.new(request_config)
        # Sign request: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Sigv4/Signer.html#sign_request-instance_method
        signature   = signer.sign_request(http_method: http_method, url: url)

        # Request Headers
        headers = signature.headers.merge({
            'x-amz-access-token' => request_grantless_access_token['access_token'],
            'user-agent' => "App/1.0 (Language=Ruby)",
            'content-type' => "application/json",
        })

        puts "---- AWS SIGN ----"
        puts "CANONICAL REQUEST: #{signature.canonical_request}"
        puts "HEADERS: #{headers}"
        puts "--------"

        conn = Faraday.new(url: url, headers: headers) do |f|
            f.response :logger # log requests and responses to $stdout
        end

        response = conn.send(http_method.downcase.to_sym) do |req|
            req.body = nil
        end

        return response

4

0 回答 0