python AWS boto3为文件上传创建预先签名的url

Bri*_*ley 2 python file-upload amazon-s3 pre-signed-url boto3

我正在为客户端将视频文件上传到 s3 的应用程序编写 django 后端。我想使用预先签名的 url,因此 django 服务器将对 url 进行签名并将其传递回客户端,然后客户端将他们的视频上传到 s3。问题是, generate_presigned_url 方法似乎不知道 s3 客户端 upload_file 方法......

按照这个例子,我使用下面的代码来生成上传的 url:

s3_client = boto3.client('s3')
try:
    s3_object_name = str(uuid4()) + file_extension
    params = {
        "file_name": local_filename,
        "bucket": settings.VIDEO_UPLOAD_BUCKET_NAME,
        "object_name": s3_object_name,
    }
    response = s3_client.generate_presigned_url(ClientMethod="upload_file",
                                                Params=params,
                                                ExpiresIn=500)
except ClientError as e:
    logging.error(e)
    return HttpResponse(503, reason="Could not retrieve upload url.")
Run Code Online (Sandbox Code Playgroud)

运行它时,我收到错误:

文件“/Users/bridgedudley/.local/share/virtualenvs/ShoMe/lib/python3.6/site-packages/botocore/signers.py”,第 574 行,在 generate_presigned_url operation_name = self._PY_TO_OP_NAME[client_method] KeyError: 'upload_file '

触发异常:

botocore.exceptions.UnknownClientMethodError:客户端没有方法:upload_file

调试后,我发现 self._PY_TO_OP_NAME 字典仅包含此处提供的 s3 客户端命令的一个子集: 在此处输入图片说明

向下滚动到“上传”... 在此处输入图片说明

没有upload_file 方法!我使用“list_buckets”尝试了相同的代码,它工作得很好,给了我一个预先签名的 url,在签名者的凭据下列出了存储桶。

因此,如果没有 generate_presigned_url 函数中可用的 upload_file 方法,我该如何实现我想要的功能?

谢谢!

Nie*_*ano 5

除了已经提到的用法:

boto3.client('s3').generate_presigned_url('put_object', Params={'Bucket':'your-bucket-name', 'Key':'your-object-name'})
Run Code Online (Sandbox Code Playgroud)

您还可以使用:

boto3.client('s3').generate_presigned_post('your-bucket_name', 'your-object_name')
Run Code Online (Sandbox Code Playgroud)

参考:https : //boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html#generating-a-presigned-url-to-upload-a-file

URL的示例生成:

import boto3

bucket_name = 'my-bucket'
key_name = 'any-name.txt'

s3_client = boto3.client('s3')
upload_details = s3_client.generate_presigned_post(bucket_name, key_name)

print(upload_details)
Run Code Online (Sandbox Code Playgroud)

输出:

{'url': 'https://my-bucket.s3.amazonaws.com/', 'fields': {'key': 'any-name.txt', 'AWSAccessKeyId': 'QWERTYUOP123', 'x-amz-security-token': 'a1s2d3f4g5h6j7k8l9', 'policy': 'z0x9c8v7b6n5m4', 'signature': 'qaz123wsx456edc'}}
Run Code Online (Sandbox Code Playgroud)

文件上传示例:

import requests

filename_to_upload = './some-file.txt'

with open(filename_to_upload, 'rb') as file_to_upload:
    files = {'file': (filename_to_upload, file_to_upload)}
    upload_response = requests.post(upload_details['url'], data=upload_details['fields'], files=files)

print(f"Upload response: {upload_response.status_code}")
Run Code Online (Sandbox Code Playgroud)

输出:

Upload response: 204
Run Code Online (Sandbox Code Playgroud)

补充说明:

正如记录的那样:

预签名 URL 使用的凭证是生成 URL 的 AWS 用户的凭证。

因此,请确保执行此生成预签名 URL 的实体允许策略s3:PutObject能够使用签名 URL 将文件上传到 S3。创建后,可以通过不同方式对其进行配置。他们之中有一些是:

作为 Lambda 函数的允许策略

或通过 boto3:

s3_client = boto3.client('s3',
        aws_access_key_id="your-access-key-id",
        aws_secret_access_key="your-secret-access-key",
        aws_session_token="your-session-token",  # Only for credentials that has it
    )
Run Code Online (Sandbox Code Playgroud)

或者在工作环境上:

# Run in the Linux environment
export AWS_ACCESS_KEY_ID="your-access-key-id"
export AWS_SECRET_ACCESS_KEY="your-secret-access-key"
export AWS_SESSION_TOKEN="your-session-token",  # Only for credentials that has it
Run Code Online (Sandbox Code Playgroud)

或者通过库,例如 Django 的 django-storages