我必须按照本指南对 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