为什么Amazon SES接受我的get请求,但拒绝我类似结构的发布请求?

时间:2019-03-26 17:26:53

标签: python amazon-web-services post python-requests amazon-ses

这是我当前用于通过Amazon的Simple email服务发送电子邮件的get请求的代码:

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签名过程的Amazon文档:https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html

我还使用完整的获取和发布请求示例,这些示例可在以下位置找到SES:https://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface-examples.html

由于某种原因,它不起作用。我尝试将我的发布请求中的kwarg从params更改为json再更改为data。

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'ArbiBushka717@gmail.com',%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'ArbiBushka717@gmail.com'%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>

每种形式的发布请求都会给出不同的错误。有没有组织帖子请求(或对Amazon API的请求)的经验的人知道我在做什么错吗?

在任何人写“使用他们的Python SDK”之前。我不能他们的SDK被阻止,我必须异步执行此操作。我计划从请求移到aiohttp。我现在试图在请求中获取此信息,因为在此问题中输入此问题更简单。

如果可以的话请帮助,谢谢阅读。

1 个答案:

答案 0 :(得分:0)

等待我到的nvm。要在请求中指定正文,请使用“数据”参数。

我的变量request_parameters的格式必须为param1=This&param2=that

哇,好头疼。