首页 网维知识库 Python利用S3的Presigned URLs实现无鉴权上传与下载

Python利用S3的Presigned URLs实现无鉴权上传与下载

S3协议操作对象存储服务,通常是实现上传下载功能。 但是在某些场景下,程序不具备操作权限,或为了安全原因而缩小权限配置,需要实现无鉴权的上传与下载。 这时可以用S3协议的Presi…

S3协议操作对象存储服务,通常是实现上传下载功能。 但是在某些场景下,程序不具备操作权限,或为了安全原因而缩小权限配置,需要实现无鉴权的上传与下载。 这时可以用S3协议的Presigned URLs来实现无鉴权读写操作。

Python利用S3的Presigned URLs实现无鉴权上传与下载插图

推荐使用PUT而不是POST来实现上传,因为PUT使用起来比较简单。

PUT上传

import boto3

def gen_s3_presigned_put(bucket: str, path: str) -> str:
    s3r = boto3.resource(
        's3',
        endpoint_url=S3_ENDPOINT,
        aws_access_key_id=S3_ACCESS_KEY,
        aws_secret_access_key=S3_SECRET_KEY,
        region_name=S3_REGION,
        config=Config(signature_version='s3v4'),
    )
    if not s3r.Bucket(bucket).creation_date:
        s3r.create_bucket(Bucket=bucket)
    return s3r.meta.client.generate_presigned_url(
        ClientMethod='put_object',
        Params={
            'Bucket': bucket,
            'Key': path,
        },
        ExpiresIn=3600,
        HttpMethod='PUT',
    )

url = generate_presigned_put('bucket', 'remote/path/of/file')

generate_presigned_url的源码可见botocore/signers.py#L245

这里的返回值,就是一个在1小时内可以用PUT上传的URL字符串。 通过某种方式传递URL到无鉴权的服务或客户端,就可以实现上传功能。

S3_*等,就是鉴权信息。生成URL需要鉴权信息,使用时则不用。 上面代码中,还包含一个if判定桶的存在性并自动建立的功能。 它在生产环境基本无用,但是方便调试,可以酌情去掉。

以下是上传示例:

import requests

def upload_with_put(url):
    with open('local/path/of/file', 'rb') as file:
        response = requests.put(url, data=file)
        response.raise_for_status()

GET下载

import boto3

def gen_s3_presigned_get(bucket: str, path: str) -> str:
    s3r = boto3.resource(
        's3',
        endpoint_url=S3_ENDPOINT,
        aws_access_key_id=S3_ACCESS_KEY,
        aws_secret_access_key=S3_SECRET_KEY,
        region_name=S3_REGION,
        config=Config(signature_version='s3v4'),
    )
    if not s3r.Bucket(bucket).creation_date:
        s3r.create_bucket(Bucket=bucket)
    return s3r.meta.client.generate_presigned_url(
        ClientMethod='get_object',
        Params={
            'Bucket': bucket,
            'Key': path,
        },
        ExpiresIn=3600,
        HttpMethod='GET',
    )

url = generate_presigned_get('bucket', 'remote/path/of/file')

整个实现和PUT非常类似,只是改了ClientMethodHttpMethod

以下是下载示例:

size = 2**12  # Use 4 KB memery buffer
with open(path, 'wb') as file:
    for chunk in response.iter_content(chunk_size=size):
        file.write(chunk)

POST上传

import boto3

def gen_s3_presigned_post(bucket: str, path: str) -> str:
    s3r = boto3.resource(
        's3',
        endpoint_url=S3_ENDPOINT,
        aws_access_key_id=S3_ACCESS_KEY,
        aws_secret_access_key=S3_SECRET_KEY,
        region_name=S3_REGION,
        config=Config(signature_version='s3v4'),
    )
    if not s3r.Bucket(bucket).creation_date:
        s3r.create_bucket(Bucket=bucket)
    dict_ = s3r.meta.client.generate_presigned_post(
        Bucket=bucket,
        Key=path,
        ExpiresIn=3600,
    )
    return dict_['url'], dict_['fields']

url, fields = generate_presigned_post('bucket', 'remote/path/of/file')

generate_presigned_post的源码可见botocore/signers.py#L605。 除了URL外,fields是个dict,也是必须要传递的参数。 并且似乎需要传递或约定path,也可能使用通用的file也行。

import requests

def upload_with_post(url, fields):
    with open('local/path/of/file', 'rb') as file:
        files = {'file': ('remote/path/of/file', file)}
        response = requests.post(url, data=fields, files=files)
        response.raise_for_status()

HTML网页示例如下,其中也可发现fields中包含的具体内容。:



    

      

    File:
       

总结

同样是上传,用POST就会麻烦一些,因此推荐PUT。 二者的区别,可能在于操作的幂等性,POST是不能重复的,而PUT可以。 (仅语义推断,未实测验证。)

分段上传,用Presigned URLs似乎是不支持的。

免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。

作者: 3182235786a

为您推荐

Windows系统怎么保持远程桌面长时间链接不会自动断开呢?

Windows系统怎么保持远程桌面长时间链接不会自动断开呢?

大家经常会遇到正在远程桌面连接如果不进行一些操作,过上个几分钟一会儿之后远程桌面连接就会需要登录,有时还是直接断开需要重...
Win11预览版 Builds 22572.100更新补丁KB5012817发布(附更新修复内容汇总)

Win11预览版 Builds 22572.100更新补丁KB5012817发布(附更新修复内容汇总)

据系统之家小编了解,微软公司于今日凌晨面向Windows预览频道发布了新的Win11 KB5012817补丁,内部版本2...
Win11预览版全新标签式文件资源管理器上手体验:快速切换窗口,还可以滚动标签

Win11预览版全新标签式文件资源管理器上手体验:快速切换窗口,还可以滚动标签

据 Windows Latest 报道,如果你是众多要求微软为文件资源管理器添加标签页的用户之一,现在终于等到了好消息。...
微软 Win11 22H2“太阳谷 2”重大版本将全面改造升级传统经典 UI

微软 Win11 22H2“太阳谷 2”重大版本将全面改造升级传统经典 UI

据 Windows Latest 报道,Windows 11 太阳谷 2 更新预计将对 UI 进行大修,并在 WinUI...
电脑升级win11后怎么退回win10?win11退回win10系统操作方法

电脑升级win11后怎么退回win10?win11退回win10系统操作方法

方法一 1.当我们升级win11后需要退回win10系统时,首先进入开始菜单页面,找到【设置】。 2.在设置的操作页面中...

发表回复

返回顶部