Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 有没有办法使用AWS签名的URL执行多部分上载?_Python_Amazon Web Services_Boto - Fatal编程技术网

Python 有没有办法使用AWS签名的URL执行多部分上载?

Python 有没有办法使用AWS签名的URL执行多部分上载?,python,amazon-web-services,boto,Python,Amazon Web Services,Boto,我正在为一个服务编写一个客户端,该服务为上传提供一个签名url。这对于较小的上传效果很好,但对于使用多部分上传的较大上传效果不佳 授权文档建议我可以在URL中或通过授权标头使用提供的签名和访问密钥id。我曾尝试使用header方法来启动多部分上传,但访问被拒绝。当我使用查询字符串方法时,我得到了一个不允许的方法(在本例中为POST) 我正在使用boto生成URL。例如: import boto c = boto.connect_s3() bucket = c.get_bucket('my-bu

我正在为一个服务编写一个客户端,该服务为上传提供一个签名url。这对于较小的上传效果很好,但对于使用多部分上传的较大上传效果不佳

授权文档建议我可以在URL中或通过授权标头使用提供的签名和访问密钥id。我曾尝试使用header方法来启动多部分上传,但访问被拒绝。当我使用查询字符串方法时,我得到了一个不允许的方法(在本例中为POST)

我正在使用boto生成URL。例如:

import boto

c = boto.connect_s3()
bucket = c.get_bucket('my-bucket')
key = boto.s3.key.Key(bucket, 'my-big-file.gz')
signed_url = key.generate_url(60 * 60, 'POST')  # expires in an hour
然后,当尝试使用已签名的URL启动多部分上载时,我将执行以下操作:

import requests

url = signed_url + '&uploads'
resp = requests.post(url)
这将返回一个不允许的方法

这种策略可行吗?是否有更好的方法向特定资源提供有限的凭据,以便允许大型多部分上载

更新

我已经设法找到了一个稍微更具体的错误,使我认为这是不可能的。不幸的是,我得到一个403,说签名与请求不匹配

<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>SignatureDoesNotMatch</Code>
  <Message>The request signature we calculated does not match the signature you
  provided. Check your key and signing method.</Message>
  <StringToSignBytes>.../StringToSignBytes>
  <RequestId>...</RequestId>
  <HostId>...</HostId>
  <SignatureProvided>...</SignatureProvided>
  <StringToSign>POST


  1402941975
  /my-sandbox/test-mp-upload.txt?uploads</StringToSign>
  <AWSAccessKeyId>...</AWSAccessKeyId>
</Error>
这使我认为我将无法使用签名的URL,因为签名不匹配

更新

我已经决定使用一个已签名的URL来进行多个部分的上传是不合理的。虽然我怀疑它是技术上可行的,但它并不实用。原因是,一个已签名的URL要求URL、页眉和请求方法完全匹配,以便按照预期的工作。因为多个部分的上传需要初始化上传,上传每个PAR。t并完成(或取消)上传,为每个步骤生成URL将是一件痛苦的事情


相反,我发现我可以创建一个联邦令牌来提供对bucket中特定密钥的读/写访问。这更加实用和简单,因为我可以像使用凭据一样立即使用boto。

要回答我自己的问题,最好的选择是使用安全令牌服务来生成一组临时凭据。可以提供策略说明,以将凭据限制为特定的存储桶和密钥。

以下是一些代码,以便为下一个要执行此操作的人节省时间:

import json
from uuid import uuid4

import boto3


def get_upload_credentials_for(bucket, key, username):
    arn = 'arn:aws:s3:::%s/%s' % (bucket, key)
    policy = {"Version": "2012-10-17",
              "Statement": [{
                  "Sid": "Stmt1",
                  "Effect": "Allow",
                  "Action": ["s3:PutObject"],
                  "Resource": [arn],
              }]}
    client = boto3.client('sts')
    response = client.get_federation_token(
        Name=username, Policy=json.dumps(policy))
    return response['Credentials']


def client_from_credentials(service, credentials):
    return boto3.client(
        service,
        aws_access_key_id=credentials['AccessKeyId'],
        aws_secret_access_key=credentials['SecretAccessKey'],
        aws_session_token=credentials['SessionToken'],
    )


def example():
    bucket = 'mybucket'
    filename = '/path/to/file'

    key = uuid4().hex
    print(key)

    prefix = 'tmp_upload_'
    username = prefix + key[:32 - len(prefix)]
    print(username)
    assert len(username) <= 32  # required by the AWS API

    credentials = get_upload_credentials_for(bucket, key, username)
    client = client_from_credentials('s3', credentials)
    client.upload_file(filename, bucket, key)
    client.upload_file(filename, bucket, key + 'bob')  # fails


example()
导入json
从uuid导入uuid4
进口boto3
def get_upload_凭证(存储桶、密钥、用户名):
arn='arn:aws:s3::%s/%s'(桶,键)
政策={“版本”:“2012-10-17”,
“声明”:[{
“Sid”:“Stmt1”,
“效果”:“允许”,
“操作”:[“s3:PutObject”],
“资源”:[arn],
}]}
client=bot3.client('sts')
response=client.get\u联合\u令牌(
Name=username,Policy=json.dumps(策略))
返回响应['Credentials']
def client_from_凭据(服务、凭据):
返回boto3.client(
服务
aws_access_key_id=凭证['AccessKeyId'],
aws_secret_access_key=凭证['SecretAccessKey'],
aws_会话_令牌=凭据['SessionToken'],
)
def示例():
bucket='mybucket'
文件名='/path/to/file'
key=uuid4().hex
打印(键)
前缀='tmp_upload_'
用户名=前缀+键[:32-len(前缀)]
打印(用户名)

断言len(用户名)我想url应该是这样的:
POST/ObjectName?uploads…
,您是否尝试将
upload
关键字放在key name之后?@mr0re1很好。我更新了问题,但它没有改变任何内容。它改变了响应错误,
signaturedesnotmatch
而不是
notallowed
,这意味着请求无效st syntaxI认为这应该是公认的答案-@elarsonI知道它已经有很长一段时间没有得到回答了,但是你有没有可能成功地采用了这种方法?