python-3.x Boto3 generate_presigned_url,SignatureDoesNotMatch错误

qncylg1j  于 2023-10-21  发布在  Python
关注(0)|答案(4)|浏览(142)

SO和其他地方的几个问题和答案概述了解决从boto3 SDK调用“generate_presigned_url”时抛出的SignatureDoesNotMatch错误的可能解决方案。boto3中很少有,大多数答案建议获取新凭据来解决此异常。你可以看到更多(但这是在PHP中)here
但是这些对我不起作用,因为我使用了正确的凭证和正确的bucket名称和密钥路径。
最初,我调用这个函数是为了生成我的客户端,然后调用generate_presigned_url。

client_s3 = boto3.client(
    's3',
    # Hard coded strings as credentials, not recommended.
    aws_access_key_id='XXX',
    aws_secret_access_key='XXX',
    region_name='us-east-2',
    # EDIT: Previously, I used signature_version='v4' here, but as a user here pointed out, this might not work. Regardless, I tried 's3v4' prior to trying 'v4' and neither worked for me.
    config=Config(signature_version='s3v4')
)

url = client_s3.generate_presigned_url(
    ClientMethod='get_object',
    Params={
        'Bucket': 'BUCKET_NAME',
        'Key': 'CORRECT_KEY'
    }
)

当使用的所有参数看起来都是正确的时候,是什么原因导致了这个错误呢?我该如何解决?

wxclj1h5

wxclj1h51#

在boto3的文档中明确提到,该选项应该看起来像config=Config(signature_version='s3v4')v4不能用
这是一个boto3文档的例子。

import boto3
from botocore.client import Config

# Get the service client with sigv4 configured
s3 = boto3.client('s3', config=Config(signature_version='s3v4'))

# Generate the URL to get 'key-name' from 'bucket-name'
url = s3.generate_presigned_url(
    ClientMethod='get_object',
    Params={
        'Bucket': 'bucket-name',
        'Key': 'key-name'
    }
)

顺便说一句,us-east-2只允许签名版本4,所以你不需要指定。看看这个

nr9pn0ug

nr9pn0ug2#

我知道这有点晚了,但我按照this GitHub链接中指定的方法解决了我的问题。

import boto3
import requests

parts = s3_client.generate_presigned_post(Bucket=bucket_name,
                                          Key=key,
                                          Fields={
                                            'acl': 'public-read',
                                            'Content-MD5': str(md5),
                                            'Content-Type': 'binary/octet-stream'
                                            },
                                          Conditions=[
                                              {"acl": "public-read"},
                                              ["starts-with", "$Content-Type", ""],
                                              ["starts-with", "$Content-MD5", ""]
                                          ]
                                      )

url = parts['url']
data = parts['fields']
files = {'file': open(local_path, 'rb')} # the key supposed to be file may be
response = requests.post(url, data=data, files=files)
vqlkdk9b

vqlkdk9b3#

我来晚了,但我有一个对我有效的解决方案,我希望它也能对其他人有效。

s3_client: Session = boto3.client(
        "s3",
        aws_access_key_id=kwargs["aws_access_key_id"],
        aws_secret_access_key=kwargs["aws_secret_access_key"],
        config=Config(
            signature_version="s3v4",
            region_name="us-east-2",
        ),
    )

    response: str = s3_client.generate_presigned_url(
        "put_object",
        Params={"Bucket": "example-bucket", "Key": "subfolder/file_name.zip"},
        ExpiresIn=expiration,
    )

响应将包含预签名的URL。然后,我将URL粘贴到Postman中进行测试,并确保使用PUT而不是POST,并将文件作为二进制负载添加。我已经测试并验证了这个方法。

qojgxg4l

qojgxg4l4#

在看到这个AWS forum之后,我想可能有什么可疑的事情发生了,但我真的只是想用一个安全的解决方案来解决这个问题。
我的解决方案肯定不是对每个人都是最佳的,但它对我很有效。
我将所有内容从'us-east-2'中的存储桶复制到'us-east-1'中的新存储桶中,并且我能够使用完全相同的访问/密钥和存储桶/密钥路径正确访问该存储桶。我只是使用:

client_s3 = boto3.client(
    's3',
    # Hard coded strings as credentials, not recommended.
    aws_access_key_id='XXX',
    aws_secret_access_key='XXX'
)

如果你和我一样,不想花几个小时试图破译AWS的可怜的文档,只要这样做,如果你可以。如果您有 * 真实的 * 解决方案,请在此添加。
我仍然不确定是什么原因造成的,但可能与“v4”签名方法有关,这是区域相关的。

相关问题