python - 将 AWS API 与 Python 结合使用以使用 Polly 服务

标签 python amazon-web-services amazon-polly

由于我没有成功将 boto3 集成到 Google App Engine,我尝试直接使用文档使用 API:因为 Polly(文本到语音 API)使用签名版本 4 过程,我引用了:

http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html

这是给定的脚本:

#http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html

# AWS Version 4 signing example

# EC2 API (DescribeRegions)

# See: http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
# This version makes a GET request and passes the signature
# in the Authorization header.
import sys, os, base64, datetime, hashlib, hmac
sys.path.append('../')
import requests # pip install requests

# Read AWS access key from env. variables or configuration file. Best practice is NOT
# to embed credentials in code.
access_key = os.environ.get('AWS_ACCESS_KEY_ID')
secret_key = os.environ.get('AWS_SECRET_ACCESS_KEY')
if access_key is None or secret_key is None:
    print 'No access key is available.'
    sys.exit()

# ************* REQUEST VALUES *************
method = 'GET'
##service = 'ec2'
##host = 'ec2.amazonaws.com'
##region = 'us-east-1'
##endpoint = 'https://ec2.amazonaws.com'
##request_parameters = 'Action=DescribeRegions&Version=2013-10-15'
##### START MODIFIED VALUES #######
service='polly'
host='polly.eu-west-1.amazonaws.com'
region='eu-west-1'
endpoint='https://'+host+'/v1/voices'
request_parameters='LanguageCode=en-US'
####### END MODIFIED VALUES #######

# Key derivation functions. See:
# http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-python
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

# Create a date for headers and the credential string
t = datetime.datetime.utcnow()
amzdate = t.strftime('%Y%m%dT%H%M%SZ')
datestamp = t.strftime('%Y%m%d') # Date w/o time, used in credential scope


# ************* TASK 1: CREATE A CANONICAL REQUEST *************
# http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html

# Step 1 is to define the verb (GET, POST, etc.)--already done.

# Step 2: Create canonical URI--the part of the URI from domain to query 
# string (use '/' if no path)
canonical_uri = '/' 

# Step 3: Create the canonical query string. In this example (a GET request),
# request parameters are in the query string. Query string values must
# be URL-encoded (space=%20). The parameters must be sorted by name.
# For this example, the query string is pre-formatted in the request_parameters variable.
canonical_querystring = request_parameters

# Step 4: Create the canonical headers and signed headers. Header names
# must be trimmed and lowercase, and sorted in code point order from
# low to high. Note that there is a trailing \n.
canonical_headers = 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n'

# Step 5: Create the list of signed headers. This lists the headers
# in the canonical_headers list, delimited with ";" and in alpha order.
# Note: The request can include any headers; canonical_headers and
# signed_headers lists those that you want to be included in the 
# hash of the request. "Host" and "x-amz-date" are always required.
signed_headers = 'host;x-amz-date'

# Step 6: Create payload hash (hash of the request body content). For GET
# requests, the payload is an empty string ("").
payload_hash = hashlib.sha256('').hexdigest()

# Step 7: Combine elements to create create canonical request
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash


# ************* TASK 2: CREATE THE STRING TO SIGN*************
# Match the algorithm to the hashing algorithm you use, either SHA-1 or
# SHA-256 (recommended)
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
string_to_sign = algorithm + '\n' +  amzdate + '\n' +  credential_scope + '\n' +  hashlib.sha256(canonical_request).hexdigest()


# ************* TASK 3: CALCULATE THE SIGNATURE *************
# Create the signing key using the function defined above.
signing_key = getSignatureKey(secret_key, datestamp, region, service)

# Sign the string_to_sign using the signing_key
signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()


# ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
# The signing information can be either in a query string value or in 
# a header named Authorization. This code shows how to use a header.
# Create authorization header and add to request headers
authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' +  'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature

# The request can include any headers, but MUST include "host", "x-amz-date", 
# and (for this scenario) "Authorization". "host" and "x-amz-date" must
# be included in the canonical_headers and signed_headers, as noted
# earlier. Order here is not significant.
# Python note: The 'host' header is added automatically by the Python 'requests' library.
headers = {'x-amz-date':amzdate, 'Authorization':authorization_header}


# ************* SEND THE REQUEST *************
request_url = endpoint + '?' + canonical_querystring

print '\nBEGIN REQUEST++++++++++++++++++++++++++++++++++++'
print 'Request URL = ' + request_url
print 'Header'
print headers

r = requests.get(request_url, headers=headers)

print '\nRESPONSE++++++++++++++++++++++++++++++++++++'
print 'Response code: %d\n' % r.status_code
print r.text

然后我收到错误消息:

BEGIN REQUEST++++++++++++++++++++++++++++++++++++
Request URL = https://polly.eu-west-1.amazonaws.com/v1/voices?LanguageCode=en-US

RESPONSE++++++++++++++++++++++++++++++++++++
Response code: 403

{"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.\n\nThe Canonical String for this request should have been\n'GET\n/v1/voices\nLanguageCode=en-US\nhost:polly.eu-west-1.amazonaws.com\nx-amz-date:20170122T160127Z\n\nhost;x-amz-date\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'\n\nThe String-to-Sign should have been\n'AWS4-HMAC-SHA256\n20170122T160127Z\n20170122/eu-west-1/polly/aws4_request\n6e1004fbcc11a73baa0c7fe9ff8d5629bada5061fdc8b03fbf307696ea41728d'\n"}

我该如何调试它? 我怀疑这不是 secret key 问题,因为它们在 boto3 中工作

最佳答案

我强烈建议您手动构建自己的 HTTP 请求以与 AWS 服务交互。自己构建 AWS 签名,您将进入一个充满 403 错误、痛苦和苦难的无尽世界。

在 Python 环境中使用 boto3 确实是唯一值得推荐的方法。

(顺便说一句,this might help youboto3 在您的本地开发服务器中工作)

关于python - 将 AWS API 与 Python 结合使用以使用 Polly 服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41793119/

相关文章:

amazon-web-services - 亚马逊 "Lex & Polly"与 "Alexa Voice services + Alexa skill kit"之间的区别

python - 显示所有 jinja 对象属性

python - TOML,YAML和StrictYAML

iphone - svn 更新未声明标识符后的 S3TransferManager

amazon-web-services - 如何为 aws appconfig 创建托管配置版本

php - 使用 PHP SDK 的 Amazon Polly 实现

python - mongodb 在聚合时从同一文档的数组中获取唯一值

python - 更改目录和重命名问题

.net - AWS AmazonComprehend 示例在 .net C# 中运行时遇到问题

node.js - 如何使用 aws polly api tts 网页并保存在 aws s3 中