为什么Amazon SES接受我的获取请求,但拒绝我的类似结构的帖子请求?

问题描述 投票:0回答:1

这是我目前用于通过亚马逊的简单电子邮件服务发送电子邮件的获取请求的代码:

import datetime
import hashlib
import hmac
import urllib.parse
import requests


def sign(key, msg):
    return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()


def getSignatureKey(key, dateStamp, regionName, serviceName):
    kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
    kRegion = sign(kDate, regionName)
    kService = sign(kRegion, serviceName)
    kSigning = sign(kService, 'aws4_request')
    return kSigning


method = 'GET'
service = 'ses'
host = 'email.us-east-1.amazonaws.com'
region = 'us-east-1'
endpoint = 'https://email.us-east-1.amazonaws.com/'
access_key = 'my_access_key'
secret_key = 'my_secret_key'
my_email = 'my_email_address'

t = datetime.datetime.utcnow()
amz_date = t.strftime('%Y%m%dT%H%M%SZ')
datestamp = t.strftime('%Y%m%d')
canonical_uri = '/'
canonical_headers = 'host:' + host + '\n'
signed_headers = 'host'
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'

canonical_querystring_part1 = 'Action=SendEmail' \
                              '&Destination.ToAddresses.member.1={}' \
                              '&Message.Body.Html.Charset=UTF-8' \
                              '&Message.Body.Html.Data={}' \
                              '&Message.Body.Text.Charset=UTF-8' \
                              '&Message.Body.Text.Data={}' \
                              '&Message.Subject.Charset=UTF-8' \
                              '&Message.Subject.Data={}' \
                              '&Source={}'.format(urllib.parse.quote(my_email, safe=''), 
                                                  urllib.parse.quote('<b>Html Hello.</b>', safe=''), 
                                                  urllib.parse.quote('Non Html hello.', safe=''),
                                                  urllib.parse.quote('Asyncio Subject line.', safe=''), 
                                                  urllib.parse.quote(my_email, safe=''))
canonical_querystring_part2 = '&X-Amz-Algorithm=AWS4-HMAC-SHA256'
canonical_querystring_part2 += '&X-Amz-Credential=' + urllib.parse.quote_plus(access_key + '/' + credential_scope)
canonical_querystring_part2 += '&X-Amz-Date=' + amz_date
canonical_querystring_part2 += '&X-Amz-Expires=30'
canonical_querystring_part2 += '&X-Amz-SignedHeaders=' + signed_headers
canonical_querystring = canonical_querystring_part1 + canonical_querystring_part2

payload_hash = hashlib.sha256(''.encode('utf-8')).hexdigest()
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()

signing_key = getSignatureKey(secret_key, datestamp, region, service)
signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()

canonical_querystring += '&X-Amz-Signature=' + signature
request_url = endpoint + "?" + canonical_querystring


r = requests.get(request_url)

它有点长,但运行正常。这是我尝试完全相同的事情,但有一个帖子请求:

import datetime
import hashlib
import hmac
import requests


def sign(key, msg):
    return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()


def getSignatureKey(key, dateStamp, regionName, serviceName):
    kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
    kRegion = sign(kDate, regionName)
    kService = sign(kRegion, serviceName)
    kSigning = sign(kService, 'aws4_request')
    return kSigning


method = 'POST'
service = 'ses'
host = 'email.us-east-1.amazonaws.com'
region = 'us-east-1'
endpoint = 'https://email.us-east-1.amazonaws.com/'
access_key = 'my_access_key'
secret_key = 'my_secret_key'
my_email = 'my_email_address'


content_type = 'application/x-www-form-urlencoded; charset=utf-8'


# Request parameters for CreateTable--passed in a JSON block.
request_parameters = '{'
request_parameters += "'body': {'Action': 'SendEmail', 'Destination.ToAddresses.member.1': '%s', 'Message.Body.Html.Charset': 'UTF-8', " \
                      "'Message.Body.Html.Data': 'HTMLMESSAGE', 'Message.Body.Text.Charset': 'UTF-8', 'Message.Body.Text.Data': 'nonHTMLmessage', 'Message.Subject.Charset': 'UTF-8', " \
                      "'Message.Subject.Data': 'subject','Source': '%s'}, " % (my_email, my_email)
request_parameters += "'Content-Type': '%s', " % content_type
request_parameters += "'context': {'client_region': 'us-east-1'}"
request_parameters += '}'


t = datetime.datetime.utcnow()
amz_date = t.strftime('%Y%m%dT%H%M%SZ')
date_stamp = t.strftime('%Y%m%d')


canonical_uri = '/'
canonical_querystring = ''
canonical_headers = 'content-type:' + content_type + '\n' + 'host:' + host + '\n' + 'x-amz-date:' + amz_date + '\n'
signed_headers = 'content-type;host;x-amz-date'

payload_hash = hashlib.sha256(request_parameters.encode('utf-8')).hexdigest()

canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = date_stamp + '/' + region + '/' + service + '/' + 'aws4_request'

string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
signing_key = getSignatureKey(secret_key, date_stamp, region, service)
signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()

authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
headers = {'Content-Type': content_type, 'X-Amz-Date': amz_date, 'Authorization': authorization_header}


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

我尽可能地遵循亚马逊的文档来进行v4签名过程:https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html

我还使用了他们在这里找到的SES的完整的get和post请求示例:https://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface-examples.html

由于某种原因,它无法正常工作。我尝试将我的帖子请求中的kwarg从params更改为json到数据。

r = requests.post(endpoint, params=request_parameters, headers=headers)
<IncompleteSignatureException>
  <Message>When Content-Type:application/x-www-form-urlencoded, URL cannot include query-string parameters (after '?'): '/?%7B'body':%20%7B'Action':%20'SendEmail',%20'Destination.ToAddresses.member.1':%20'[email protected]',%20'Message.Body.Html.Charset':%20'UTF-8',%20'Message.Body.Html.Data':%20'HTMLMESSAGE',%20'Message.Body.Text.Charset':%20'UTF-8',%20'Message.Body.Text.Data':%20'nonHTMLmessage',%20'Message.Subject.Charset':%20'UTF-8',%20'Message.Subject.Data':%20'subject','Source':%20'[email protected]'%7D,%20'Content-Type':%20'application/x-www-form-urlencoded;%20charset=utf-8',%20'context':%20%7B'client_region':%20'us-east-1'%7D%7D'</Message>
</IncompleteSignatureException>

r = requests.post(endpoint, data=request_parameters, headers=headers)
<AccessDeniedException/>


r = requests.post(endpoint, json=request_parameters, headers=headers)
<InvalidSignatureException>
  <Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
</InvalidSignatureException>

每种形式的发布请求都会产生不同的错误。有结构化发布请求(或亚马逊API请求)经验的人是否知道我做错了什么?

在任何人写作之前,“使用他们的Python SDK。”我不能。他们的SDK是阻塞的,我必须异步执行此操作。我计划从请求转移到aiohttp。我正试图在现在的请求中得到这个,因为在这个问题中更容易提出这个问题。

如果可以,请帮忙,谢谢你的阅读。

python amazon-web-services post python-requests amazon-ses
1个回答
0
投票

我等到了。要在请求中指定正文,请使用“data”kwarg。

另外我的变量request_parameters需要采用param1=This&param2=that格式

哇头疼。

© www.soinside.com 2019 - 2024. All rights reserved.