python实现HTTP上传文件到AWS S3 对象(v4 signature)

获取临时令牌后将使用V4 signature签名字符串请求上传

# -*- encoding: utf-8 -*-
"""
@File    : AWSV4Signature.py
@Time    : 2023/6/6 11:38
@Author  : stephen
@Email   : dz@asj6.wecom.work
@Software: PyCharm
"""
import datetime
import hashlib
import hmac
import urllib.parse

import pytz
import requests


def get_s3_v4_signature(access_key: str, secret_key: str, session_token: str, service: str, region: str,
                        http_method: str, endpoint_url: str, path: str,
                        local_file_path: str) -> dict:
    # 获取当前时间并格式化为字符串
    timestamp = datetime.datetime.now(tz=pytz.utc).strftime('%Y%m%dT%H%M%SZ')
    datestamp = datetime.datetime.now(tz=pytz.utc).strftime('%Y%m%d')

    # 计算文件内容的 SHA-256 哈希值作为 payload hash
    with open(local_file_path, 'rb') as fi:
        payload_hash = hashlib.sha256(fi.read()).hexdigest()

    # 对 URL 进行转义以生成规范的 URI 和查询字符串
    canonical_uri = urllib.parse.quote(path)
    canonical_querystring = ''

    # 构建规范的请求头
    canonical_headers = '\n'.join([f'host:{endpoint_url}',
                                   f'x-amz-content-sha256:{payload_hash}',
                                   f'x-amz-date:{timestamp}']) + '\n'
    signed_headers = 'host;x-amz-content-sha256;x-amz-date'

    # 如果提供了会话令牌,则将其包含在规范请求头中
    if session_token:
        canonical_headers += 'x-amz-security-token:' + session_token + '\n'
        signed_headers += ';x-amz-security-token'

    # 构建规范请求
    canonical_request = '\n'.join([http_method,
                                   canonical_uri,
                                   canonical_querystring,
                                   canonical_headers,
                                   signed_headers,
                                   payload_hash])
    # 构建字符串以用于计算签名
    credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
    string_to_sign = 'AWS4-HMAC-SHA256' + '\n' + timestamp + '\n' + credential_scope + '\n' + hashlib.sha256(
        canonical_request.encode('utf-8')).hexdigest()

    # 计算签名所需的秘钥
    k_date = hmac.new(('AWS4' + secret_key).encode('utf-8'), datestamp.encode('utf-8'), hashlib.sha256).digest()
    k_region = hmac.new(k_date, region.encode('utf-8'), hashlib.sha256).digest()
    k_service = hmac.new(k_region, service.encode('utf-8'), hashlib.sha256).digest()
    k_signing = hmac.new(k_service, 'aws4_request'.encode('utf-8'), hashlib.sha256).digest()

    # 计算签名并构建授权头部
    signature = hmac.new(k_signing, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
    auth_header = 'AWS4-HMAC-SHA256' + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + \
                  'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature

    # 构建 HTTP 请求头部,并包含授权头部。如果提供了会话令牌,则也应将其包含在请求头中
    headers = {
        'host': endpoint_url,
        'x-amz-content-sha256': payload_hash,
        'x-amz-date': timestamp,
        'Authorization': auth_header
    }
    if session_token:
        headers['x-amz-security-token'] = session_token

    return headers


if __name__ == '__main__':
    # 输入您获得的临时访问令牌,包括访问密钥 ID、密钥和会话令牌。
    region_name = 'us-east-1'
    temp_access_key = 'ASIA2E'
    temp_secret_key = 'hs/M0OgjK++wmz'
    temp_session_token = "FwoGZXIvYXdzEAYaDKqiNw1jZICGs4eBRCL1AZOtnLPqc9PYruSgrRFVHS6/EK9XspDKZ3g2TJ"

    # 指定要上传的本地文件路径和 S3 存储桶中的对象 key 值,并设置请求超时时间,单位为秒。
    local_path = 'E:/stephen/testGlacier.txt'
    object_key = 'vod1/test2.txt'
    timeout_seconds = 3600
    bucket_name = 'bucket_name'

    # 初始化 S3 存储客户端
    s3_endpoint = 's3.{}.amazonaws.com'.format(region_name)
    s3_url = 'https://' + s3_endpoint
    content_type = 'text/plain'

    # 构建 HTTP 头部,包含授权信息和必要的元数据
    s3_headers = get_s3_v4_signature(temp_access_key, temp_secret_key, temp_session_token,
                                     's3', region_name, 'PUT', s3_endpoint, '/' + bucket_name + '/' + object_key,
                                     local_path)
    s3_headers['Content-Type'] = content_type

    # 构建上传文件的 URL,并将本地文件上传到指定的存储桶中
    url = s3_url + '/' + bucket_name + '/' + object_key
    with open(local_path, 'rb') as f:
        response = requests.put(url, headers=s3_headers, data=f, timeout=timeout_seconds)
        print(response.status_code)
        print(response.text)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将大文件上传到AWS S3,可以使用AWS提供的multipart上传方法。这个方法允许你将文件分成多个部分来上传,以便在网络不稳定的情况下保证上传的可靠性。以下是一个简单的Node.js示例代码: ```javascript const AWS = require('aws-sdk'); const fs = require('fs'); // AWS S3配置 const s3 = new AWS.S3({ accessKeyId: 'your_accessKeyId', secretAccessKey: 'your_secretAccessKey' }); // 文件上传配置 const uploadParams = { Bucket: 'your_bucket_name', Key: 'your_file_name', Body: '', ContentType: 'your_content_type' }; // 分块上传文件 const fileStream = fs.createReadStream('your_file_path'); fileStream.on('error', function(err) { console.log('Error:', err); }); uploadParams.Body = fileStream; const multipartUpload = new AWS.S3.ManagedUpload({ params: uploadParams, partSize: 5 * 1024 * 1024, // 分块大小,单位:字节 queueSize: 1 // 并发上传文件数量 }); multipartUpload.on('httpUploadProgress', function(progress) { console.log('Progress:', progress); }); multipartUpload.promise().then(function(data) { console.log('Success:', data); }).catch(function(err) { console.log('Error:', err); }); ``` 在上面的代码中,我们使用AWS SDK来创建S3对象,并设置了访问密钥等参数。接着,我们设置了文件上传的配置参数,包括Bucket、Key、Body、ContentType等。最后,我们使用ManagedUpload类实现将文件分块上传到S3的功能,分块大小和并发上传文件数量可以根据实际需求进行调整。在上传过程中,我们可以通过httpUploadProgress事件获取上传进度信息。最后,我们使用promise()方法来等待文件上传完成,并处理上传成功或失败的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值