Rails对接亚马逊SP API时SigV4签名不匹配报错如何解决?
我遇到的报错如下:
The request signature we calculated does not match the signature you provided
The Canonical String for this request should have been
The String-to-Sign should have been
我在Rails框架中对接亚马逊SP API的流程如下:
第一步:获取Access Token
payload = { grant_type: 'refresh_token', client_id: [ClientId], refresh_token: [RefreshToken], client_secret: [ClientSecret], } headers = {'Content-Type': 'application/json'} response = HTTParty.post("https://api.amazon.com/auth/o2/token", body: payload.to_json, headers: headers) access_token = response["access_token"]
第二步:调用AWS STS接口角色扮演获取临时凭证
sts = Aws::STS::Client.new( region: "us-east-1", credentials: Aws::Credentials.new("aws-access-key", "aws-secret-key") ) result = sts.assume_role({ role_arn: "role_arn", role_session_name: 'sp-api' })
第三步:生成SigV4签名
signer = Aws::Sigv4::Signer.new( service: 'execute-api', region: 'us-east-1', access_key_id: access_key_id, secret_access_key: secret_access_key, session_token: session_token ) signature = signer.sign_request( http_method: 'GET', url: 'https://sellingpartnerapi-na.amazon.com/orders/v0/orders/ordersID', headers: { 'host' => 'sellingpartnerapi-na.amazon.com', 'X-Amz-Access-Token' => access_token, })
第四步:携带签名调用SP API
headers = { 'Content-Type' => 'application/json', "host" => signature.headers["host"], "X-Amz-Date" => signature.headers['x-amz-date'], "X-Amz-Security-Token" => signature.headers["x-amz-security-token"], "X-Amz-Content-Sha256" => signature.headers["x-amz-content-sha256"], "Authorization" => signature.headers['authorization'] } data = HTTParty.send(:get, "https://sellingpartnerapi-na.amazon.com/orders/v0/orders/ordersID", headers: headers)
错误原因&修复方案
上述流程中存在4处可直接导致签名不匹配的问题,按优先级排查修复即可:
- STS凭证取值错误:第二步返回的
result对象才是临时凭证的载体,需要从result.credentials.access_key_id、result.credentials.secret_access_key、result.credentials.session_token三个字段取值传入第三步的签名器,不要误传入根账号的AK/SK。同时确认使用的role_arn已经完成SP API授权绑定,无权限会间接触发签名校验失败。 - 签名头包含不需要校验的字段:
X-Amz-Access-Token是SP API要求的请求头,但不属于SigV4签名的校验范围,第三步中将该字段传入sign_request的headers参数,会导致签名计算时纳入该字段,AWS校验时不校验该字段,最终签名不匹配。 - 请求时缺失
X-Amz-Access-Token头:第四步发起请求时没有携带X-Amz-Access-Token头,该头是SP API的必填字段,不需要参与签名,但请求时必须传入。 - 多余请求头干扰校验:GET请求不需要携带
Content-Type: application/json头,多余的头如果和签名时的头列表不一致也会触发校验失败。
代码修改参考
- 调整第三步签名代码,移除不需要参与签名的头:
signature = signer.sign_request( http_method: 'GET', url: 'https://sellingpartnerapi-na.amazon.com/orders/v0/orders/ordersID', headers: { 'host' => 'sellingpartnerapi-na.amazon.com' })
- 调整第四步请求头,直接合并签名返回的所有头,补充必填的SP API专属头:
headers = signature.headers.merge({ 'X-Amz-Access-Token' => access_token }) data = HTTParty.get("https://sellingpartnerapi-na.amazon.com/orders/v0/orders/ordersID", headers: headers)
通用排查方法
如果修改后仍报错,将自己生成签名时的Canonical String和报错提示的官方要求Canonical String逐字符对比,不一致的位置就是错误点,常见的差异包括路径大小写错误、query参数顺序错误、请求体哈希值不匹配。
内容的提问来源于stack exchange,提问作者Hunaid Nawaz
相关产品推荐
相关产品推荐

