React-native / AWS API 网关 android 问题

React-native / AWS API Gateway android issue

我正在尝试将 react-native 与 aws api 网关结合使用。相同的代码(纯 JS)在 ios 上运行良好,但在 android 上运行失败并出现 403 错误。

var signedRequest={
  "headers": {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "x-amz-date": "20170918T134411Z",
    "Authorization": "AWS4-HMAC-SHA256 Credential=ASIAIBC7RQ7MFUIRO7QQ/20170918/ap-northeast-1/execute-api/aws4_request, SignedHeaders=accept;content-type;host;x-amz-date, Signature=9fb6d4d4820024097f25aaa70648fxxx7a54a2db1a67d173189693dc073d0a0bac8",
    "x-amz-security-token": "AgoGb3JpZ2luEKn////////xxxG1iKJBHjjvZH0DxcSqE889Wb3Mv+8PwMqrRe/O5dFFmP+9bQj+fSwVIUvmBplKkQB62x/xTelGHoCEOPXpBWLjT2OAUaBXOti7UZyfyMNgg56/Z58yxk4o2/37xPLbhXfODaL8kydFV8IaPJjdbJIX+a0kXycPLBnVIBdukUp9cMVD27mWN41u3w0VP5J8YiMPzrDnwKtb0U37naoIaknMBqNBDkMGQyHal/TBJ3wjJvJWVntrJvex0QKD8rDLHjaoiIYjBd+a04m2pKsBQJ9WQl02TTCPgRp0bb1oARF2hz0Xpi45Ba6a6E9SAL07UcRShTwX6rmxi0dZ38mkSbBMjI45Xg8r/VaRZx6/OyCq3u+nq4bgLCOMKqb/80F"
  },
  "data": "{\"data\":{\"func\":\"checkIfFacebookSignupComplete\",\"data\":{}}}",
  "method": "POST",
  "url": "https://xxx.execute-api.ap-northeast-1.amazonaws.com/dev/user/user"
}

var apiResponse=await fetch(signedRequest.url, {

  method: signedRequest.method,
  body: signedRequest.data,
  headers: signedRequest.headers,

})
console.log("Got api response : ", apiResponse)

在 iOS 上它收到一个 HTTP 响应 200。但是,在 android 上它失败了:

“我们计算的请求签名与您提供的签名不匹配。请检查您的AWS Secret Access Key和签名方法。详情请参阅服务文档。

The Canonical String for this request should have been
'POST
/dev/user/user

accept:application/json
content-type:application/json; charset=utf-8
host:uihw7hnkn7.execute-api.ap-northeast-1.amazonaws.com
x-amz-date:20170918T134411Z

accept;content-type;host;x-amz-date
6b83b80f2875c2425c28b258886ad98603fd802095e35303a3c2a72528374fb5'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20170918T134411Z
20170918/ap-northeast-1/execute-api/aws4_request
008853cdfba53255257d9169e1a9c05500d01299da9efd4695ac8c66cb31e5e7'
"

我也试过 axios。和相同的结果。 (ios 工作正常,android 失败)我正在使用 react-native 0.42.3.

有人知道可能是什么问题吗?

经过大量挖掘后,问题似乎与此处所述有关:https://github.com/facebook/react-native/issues/14445。 android okHttp 库(react-native 内部使用)在请求中添加了 charset=utf=8。所以解决方案是用 header 计算 sig4 值,如下所示:

  var signedRequest={
  "headers": {
    "Content-Type": "pplication/json; charset=utf-8",
    "Accept": "application/json",
    "x-amz-date": "20170918T134411Z",
    "Authorization": "Calculated sig4 auth",
    "x-amz-security-token": "AgoGb3JpZ2luEKn////////xxxG1iKJBHjjvZH0DxcSqE889Wb3Mv+8PwMqrRe/O5dFFmP+9bQj+fSwVIUvmBplKkQB62x/xTelGHoCEOPXpBWLjT2OAUaBXOti7UZyfyMNgg56/Z58yxk4o2/37xPLbhXfODaL8kydFV8IaPJjdbJIX+a0kXycPLBnVIBdukUp9cMVD27mWN41u3w0VP5J8YiMPzrDnwKtb0U37naoIaknMBqNBDkMGQyHal/TBJ3wjJvJWVntrJvex0QKD8rDLHjaoiIYjBd+a04m2pKsBQJ9WQl02TTCPgRp0bb1oARF2hz0Xpi45Ba6a6E9SAL07UcRShTwX6rmxi0dZ38mkSbBMjI45Xg8r/VaRZx6/OyCq3u+nq4bgLCOMKqb/80F"
  },
  "data": "{\"data\":{\"func\":\"checkIfFacebookSignupComplete\",\"data\":{}}}",
  "method": "POST",
  "url": "https://xxx.execute-api.ap-northeast-1.amazonaws.com/dev/user/user"
}

新的 AWS Amplify 库(https://github.com/aws/aws-amplify) on the official AWS repo has support for automatic signing to API Gateway. This is part of the API module: https://github.com/aws/aws-amplify/blob/master/media/api_guide.md

您将首先安装 React Native npm 模块:

npm install aws-amplify-react-native

然后link项目:https://github.com/aws/aws-amplify/blob/master/media/quick_start.md#react-native-development

之后你可以配置APIs:

import Amplify, { API } from 'aws-amplify';
Amplify.configure(
    Auth: {
        identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',     //REQUIRED - Amazon Cognito Identity Pool ID
        region: 'XX-XXXX-X', // REQUIRED - Amazon Cognito Region
        userPoolId: 'XX-XXXX-X_abcd1234', //OPTIONAL - Amazon Cognito User Pool ID
        userPoolWebClientId: 'XX-XXXX-X_abcd1234', //OPTIONAL - Amazon Cognito Web Client ID
    },
    API: {
        endpoints: [
            {
                name: "ApiName1",
                endpoint: "https://1234567890-abcdefgh.amazonaws.com"
            },
            {
                name: "ApiName2",
                endpoint: "https://1234567890-abcdefghijkl.amazonaws.com"
            }
        ]
    }
});

随后您的 API 网关请求使用用户的凭据签名:

let apiName = 'MyApiName';
let path = '/path'; 
let myInit = { // OPTIONAL
    headers: {} // OPTIONAL
}
API.get(apiName, path, myInit).then(response => {
    // Add your code here
});

我遇到了同样的问题。 GET 在两个平台上都有效,但 POST 仅在 iOS 上有效。在使用 sigV4Client 签署请求之前将 Content-Type 设置为 "application/json; charset=utf-8" 为我修复了它。

const path = 'https://your-aws-endpoint.com';
const method = 'POST';
const queryParams = {};
const body = {};
const headers = {
    'Content-Type' = 'application/json; charset=utf-8';
};

const client = sigV4Client.newClient({
    accessKey: ACCESS_KEY,
    secretKey: SECRET_ACCESS_KEY,
    sessionToken: SESSION_TOKEN,
    region: REGION,
    endpoint: ENDPOINT,
});

const signedRequest = client.signRequest({
    method: method,
    path: path,
    headers: headers,
    queryParams: queryParams,
    body: body
});

fetch(signedRequest.url, {
    method: method,
    headers: signedRequest.headers,
    body: JSON.stringify(body)
}).then((results) => {
    ...
});