AWS HTTP API - тот же запрос, но другой ответ в запросах Python против HTTP Dart - PullRequest
4 голосов
/ 08 марта 2019

Я пытаюсь использовать AWS DynamoDB в приложении Flutter, и из-за отсутствия официального пакета AWS SDK для Dart я вынужден использовать низкоуровневый HTTP REST API.

Метод подписания AWSHTTP-запрос довольно утомителен, но, используя предоставленный AWS пример в качестве руководства, я смог довольно легко преобразовать Python в Dart строка за строкой.Конечным результатом были оба набора кода, производящие одинаковые подписи аутентификации.

Моя проблема возникла, когда я фактически отправил запрос.Python работает как положено, но отправка POST с HTTP-пакетом Dart выдает ошибку

Рассчитанная нами подпись запроса не соответствует предоставленной вами подписи.Проверьте свой секретный ключ доступа AWS и метод подписи.За подробностями обращайтесь к документации по сервису.

Я избавлю вас от фактического кода для генерации подписи аутентификации, поскольку проблема может быть воспроизведена простым отправлением того же запроса в жестком коде.См. Код Python и Dart ниже.

Примечание: верный ответ вернет

Срок действия подписи истек: 20190307T214900Z более ранний, чем 20190307T215809Z (20190307T221309Z - 15 мин.)

, поскольку подпись запроса использует текущую дату и действительна только в течение 15 минут.

***** КОД ПИТОНА *****

import requests

headers = {'Content-Type':'application/json',
           'X-Amz-Date':'20190307T214900Z',
           'X-Amz-Target':'DynamoDB_20120810.GetItem',
           'Authorization':'AWS4-HMAC-SHA256 Credential=AKIAJFZWA7QQAQT474EQ/20190307/ap-southeast-2/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=297c5a03c59db6da45bfe2fda6017f89a0a1b2ab6da2bb6e0d838ca40be84320'}

endpoint = 'https://dynamodb.ap-southeast-2.amazonaws.com/'
request_parameters =  '{"TableName": "player-exports","Key": {"exportId": {"S": "HG1T"}}}'

r = requests.post(endpoint, data=request_parameters, headers=headers)

print('Response status: %d\n' % r.status_code)
print('Response body: %s\n' % r.text)

***** DART CODE *****

import 'package:http/http.dart' as http;

void main(List<String> arguments) async {

  var headers = {'Content-Type':'application/json',
           'X-Amz-Date':'20190307T214900Z',
           'X-Amz-Target':'DynamoDB_20120810.GetItem',
           'Authorization':'AWS4-HMAC-SHA256 Credential=AKIAJFZWA7QQAQT474EQ/20190307/ap-southeast-2/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=297c5a03c59db6da45bfe2fda6017f89a0a1b2ab6da2bb6e0d838ca40be84320'};

  var endpoint = 'https://dynamodb.ap-southeast-2.amazonaws.com/';
  var request_parameters =  '{"TableName": "player-exports","Key": {"exportId": {"S": "HG1T"}}}';

  http.post(endpoint, body: request_parameters, headers: headers).then((response) {
    print("Response status: ${response.statusCode}");
    print("Response body: ${response.body}");
  });
}

Конечная точка, заголовки и тело буквально копируются и вставляются между двумя наборами кода.

Есть ли какой-то нюанс в том, как Dart HTTPработает, что мне здесь не хватает?Есть ли какое-либо преобразование заголовков или request_paramaters для map / string / json?

Одна вещь, которую я заметил, состоит в том, что в приведенном примере AWS говорится:

Для DynamoDB запросможет включать любые заголовки, но ДОЛЖЕН включать «host», «x-amz-date», «x-amz-target», «content-type» и «Authorization».За исключением заголовка авторизации, заголовки должны быть включены в значения canonical_headers и signature_headers, как отмечалось ранее.Порядок здесь не имеет значения.Примечание к Python: заголовок 'host' автоматически добавляется библиотекой Python 'запросы'.

Но

a) Когда я добавляю 'Host': 'dynamodb.ap-southeast-2.amazonaws.com 'к заголовкам в коде Dart, я получаю тот же результат

и

б) Если я посмотрю на r.request.headers после возврата запросов Python, явидно, что он добавил несколько новых заголовков (Content-Length и т. д.) автоматически, но «Host» не является одним из них.

Любые идеи, почему на первый взгляд такой же HTTP-запрос работает для запросов Python, но не для DartHTTP

1 Ответ

0 голосов
/ 12 марта 2019

Хорошо, теперь это решено.Моя проблема была частично огромной ошибкой пользователя.Я использовал новую среду IDE, и когда я сгенерировал жестко закодированный пример, который я предоставил, я все еще выполнял предыдущий файл.Глупо, глупо, глупо.

Но ...

Я смог разобраться с реальной проблемой, которая заставила меня поднять вопрос в первую очередь.Я обнаружил, что если вы установите тип содержимого «application / json» в заголовках, пакет dart HTTP автоматически добавит «; charset = utf-8».Поскольку это значение является частью подписи auth, когда AWS кодирует значения из заголовка для сравнения с сгенерированной пользователем подписью, они не совпадают.

Исправление заключается просто в том, чтобы при настройкетип содержимого заголовка, убедитесь, что вы вручную установили для него значение «application / json; charset = utf-8», а не «application / json».

После обсуждения этой «ошибки» было найдено несколько больше обсужденийфакт здесь .

...