使用 boto 的 Key.generate_url 方法将文件放在 S3 上时,如何正确传递 Content-MD5 headers?

How can I correctly pass Content-MD5 headers when putting files on S3 using boto's Key.generate_url method?

我有一个 Python 应用程序,使用 boto,我给用户一个临时 URL 来将文件上传到 S3 存储桶。

用户上传权限受限,我利用boot的Key.generate_url方法创建一个临时URL接受PUT请求。

我可以正常工作,但我想确保在我生成密钥和实际上传之间用户负载没有被修改。

因此,我正在尝试使用 S3 的 Content-MD5 支持来确保校验和匹配。

但是,当我在代码中添加 Content-MD5 headers 时,PUT 请求失败。

在下面的代码示例中,如果我为每个步骤(geturl 和 uploadfile)删除 Content-MD5 header,那么一切都会按预期进行。

请注意,我已经验证我的校验和是正确的:如果我上传的文件没有 Content-MD5 headers,然后我访问 S3 上的 MD5,它确实匹配我的本地哈希.

这是我获取密钥的方式:

# geturl
# s3key is a Key instance
# _file is a dict with some info on a file to be uploaded
s3headers = {
    'Content-Length': _file['length'],
    'Content-MD5': _file['md5']
}
s3url = s3key.generate_url(self.ACCESS_KEY_EXPIRES_IN, 'PUT',
                           headers=s3headers, force_http=True)
_parsed = compat.parse.urlparse(s3url)
_file['upload_url'] = '{0}://{1}{2}'.format(_parsed.scheme, _parsed.netloc, _parsed.path)
_file['upload_params'] = compat.parse.parse_qs(_parsed.query)

这是我上传文件的方式:

# uploadfile
headers = {'Content-Length': _file['length'],
       'Content-MD5': _file['md5'],
       'Content-Type': None,
       'Connection': None,
       'User-Agent': None,
       'Accept-Encoding': None,
       'Accept': None
}
stream = io.open(_file['local'])
response = requests.put(_file['upload_url'], data=stream, headers=headers, params=_file['upload_params'])

答案是 Python 3,在我的设置中,MD-5 散列是字节字符串,其他所有内容都是文本字符串。解决方案是在将字节字符串添加到 headers.

之前对其进行解码

以前,我的校验和 (_file['md5']) 是这样制作的:

checksum = base64.b64encode(hasher.digest())

现在是:

checksum = base64.b64encode(hasher.digest()).decode('utf-8')