AWS SP-API 请求 - 请求标头中缺少访问令牌

问题描述

我必须按照本指南对 AWS API (SP-API) 执行签名请求:https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/use-case-guides/authorization-api-use-case-guide/authorization-api-use-case-guide-v1.md

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

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

请求

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="

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

首先我请求一个无授权的访问令牌 (documentation)

    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

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...