当前位置:   article > 正文

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

python上传文件到aws对象存储

获取临时令牌后将使用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)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/707165
推荐阅读
相关标签
  

闽ICP备14008679号