30

我知道如何以这种方式下载文件:key.generate_url(3600)

但是当我尝试上传时:key.generate_url(3600, method='PUT'),网址不起作用。有人告诉我: The request signature we calculated does not match the signature you provided. Check your key and signing method.

我在主页上找不到有关boto如何使用该功能的示例代码generate_url(method='PUT')。这里有人知道如何使用它进行上传吗?如何设置上传文件路径的参数?

4

5 回答 5

48

我找到了一些时间来尝试这个,这就是我发现的。

>>> import boto
>>> c =boto.connect_s3()
>>> fp = open('myfiletoupload.txt')
>>> content_length = len(fp.read())
>>> c.generate_url(300, 'PUT', 'test-1332789015', 'foobar', headers={'Content-Length': str(content_length)}, force_http=True)
'http://test-1332789015.s3.amazonaws.com/foobar?Signature=oUARG45mR95utXsiQYRJNiCI4x4%3D&Expires=1333731456&AWSAccessKeyId=AKIAJOTCCJRP4C3NSMYA&Content-Length=16'

然后我可以使用 curl 将文件放入该 url,如下所示:

$ curl --request PUT --upload-file myfiletoupload.txt "http://test-1332789015.s3.amazonaws.com/foobar?Signature=oUARG45mR95utXsiQYRJNiCI4x4%3D&Expires=1333731456&AWSAccessKeyId=AKIAJOTCCJRP4C3NSMYA&Content-Length=16"

这导致文件被上传到存储桶。所以,看来这是可能的。您可能想查看是否可以计算 content-md5 值并将其包含在标头中,但您还必须弄清楚如何让 curl 发送该标头。此外,您应该能够通过 HTTPS 而不是 HTTP 进行这项工作,但我还没有尝试过。

于 2012-04-06T17:00:34.757 回答
35

这是在 boto3 中的样子(使用 1.2.3 版测试)。

首先,使用以下方法创建一个预签名的 url s3.generate_presigned_url

>>> import boto3
>>> s3 = boto3.client('s3')
>>> s3.generate_presigned_url('put_object', Params={'Bucket':'YourBucket', 'Key':'YourKey'}, ExpiresIn=3600, HttpMethod='PUT')
u'https://s3-ap-northeast-1.amazonaws.com/YourBucket/YourKey?AWSAccessKeyId=AKIAXXXXXXXXXXXXXXXX&Expires=1451061671&Signature=%2FtyAyCd5vrp13p%2FqLdoPkox7yTM%3D'

使用预签名 URL PUT 到 S3

$ curl \
  --request PUT \
  --upload-file path/to/file \
  "https://s3-ap-northeast-1.amazonaws.com/YourBucket/YourKey?AWSAccessKeyId=AKIAXXXXXXXXXXXXXXXX&Expires=1451061671&Signature=%2FtyAyCd5vrp13p%2FqLdoPkox7yTM%3D"
于 2015-12-25T15:47:06.787 回答
19

所有其他答案都假设文件将使用 上传curl,这在大多数 python 脚本中确实不方便。在下文中,将生成一个预签名的 url,boto3并将文件与requests库一起上传:

session = boto3.Session(aws_access_key_id="XXX", aws_secret_access_key="XXX")
s3client = session.client('s3')
url = s3client.generate_presigned_url('put_object', Params={'Bucket': 'mybucket', 'Key': 'mykey'})

requests.put(url, data=open("/path/to/file").read())
于 2016-07-26T14:04:21.837 回答
9

这是 2012 年 4 月 6 日 garnaat 回答的后续行动。

我正在生成一个签名的 URL 服务器端,我有凭据,并将其传递给客户端,以便客户端可以直接上传内容。我足够信任客户端以允许它上传任意大小的文件,但不足以为其提供安全令牌。我想避免让客户端告诉服务器其内容作为请求的一部分有多大。因此我的后续回答。

我无需在标头中指定内容长度或指定 force_http=True 即可获得 PUT 方法的签名 url。

使用 Boto 2.31.1:如 garnaat 的回答:

>>> import boto
>>> c =boto.connect_s3()

然后我使用了:

>>> temp_url = c.generate_url(seconds_available, 'PUT', bucket_name, s3_key)

这产生了以下形式的网址:

https://s3_location/bucket_name/s3_key?Signature=Ew407JMktSIcFln%2FZe00VroCmTU%3D&Expires=1405647669&AWSAccessKeyId=kM__pEQo2AEVd_Juz4Qq

然后我可以使用 curl 发布文件:

>>> os.system('curl --request PUT --upload-file true_measure/test_files/test_file_w_content.txt "'+temp_url+'"')

我确实很难弄清楚这一点,因为我通常使用python 请求来编写测试和调试;但是,当我尝试使用它将文件放入这些 boto 使用请求生成的签名 url 之一时,我遇到了身份验证失败。我还没有完全调试这个,但我怀疑这是因为与 curl 产生的相比,请求添加了一些额外的标题。

我希望这个后续答案可以减轻其他人的调试痛苦。

于 2014-07-18T17:23:47.367 回答
1

如果您使用的是 boto(不是 boto3),我能够上传工作的唯一方法是使用generate_url_sigv4. 使用 vanillagenerate_url导致与原始问题中报告的错误相同。可能有一个我不知道的 AWS 帐户设置用于控制哪个功能起作用。

在带有 boto 2.49.0 和请求 2.22.0 的 Python 解释器中:

import boto
import os
import requests
os.environ['S3_USE_SIGV4'] = 'True'
c = boto.connect_s3(host='s3.amazonaws.com')
url = c.generate_url_sigv4(3600, 'PUT', 'my-bucket-name', 'bucket-path/to/file.txt')
with open('file.txt') as f:
    resp = requests.put(url, data=f.read())

>>> resp
<Response [200]>

如果您不使用主机名连接,则在生成 URL 时会收到此错误:

boto.s3.connection.HostRequiredError: BotoClientError: When using SigV4, you must specify a 'host' parameter.

相关:
“HmacAuthV1Handler”对象没有属性“presign”是什么意思?

如果您使用的是 boto3,则预签名的 POST 似乎有更好的文档记录:
https ://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html#generating-a-presigned-上传文件的 url

于 2020-03-19T14:59:05.810 回答