有什么方法可以使用预签名的 URL 上传和强制标记?

Any way to use presigned URL uploads and enforce tagging?

提问人:deceze 提问时间:10/1/2018 更新时间:1/29/2022 访问量:6719

问:

有没有办法向客户端发出预签名 URL 以将文件上传到 S3,并确保上传的文件具有某些标签?以此处的 Python SDK 为例,这会根据需要生成一个 URL:

s3.generate_presigned_url('put_object', 
                          ExpiresIn=3600,
                          Params=dict(Bucket='foo', 
                                      Key='bar', 
                                      ContentType='text/plain', 
                                      Tagging='foo=bar'))

这在显式提供标签的同时上传时是令人满意的:

$ curl 'https://foo.s3.amazonaws.com/bar?AWSAccessKeyId=...&Signature=...&content-type=text%2Fplain&x-amz-tagging=foo%3Dbar&Expires=1538404508' \
  -X PUT
  -H 'Content-Type: text/plain' \
  -H 'x-amz-tagging: foo=bar' \
  --data-binary foobar

但是,S3 在省略 时也会接受请求,这会上传不带标签的对象。由于我无法控制客户端,因此......坏。-H 'x-amz-tagging: foo=bar'

我尝试先创建一个空对象并标记它,然后向它发出预签名 URL,但 ting 对象完全替换它,包括删除任何标签。PUT

我尝试发出预签名 URL,但这似乎根本不支持该参数:POSTtagging

s3.generate_presigned_post('foo', 'bar', {'tagging': '<Tagging><TagSet><Tag><Key>Foo</Key><Value>Bar</Value></Tag></TagSet></Tagging>'})
$ curl https://foo.s3.amazonaws.com/ \
  -F key=bar \
  -F 'tagging=<Tagging><TagSet><Tag><Key>Foo</Key><Value>Bar</Value></Tag></TagSet></Tagging>'
  -F AWSAccessKeyId=... \
  -F policy=... \
  -F signature=... \
  -F file=@/tmp/foo

<Error><Code>AccessDenied</Code><Message>Invalid according to Policy:
Extra input fields: tagging</Message>...

我只想让客户端将文件直接上传到 S3,并确保在此过程中以某种方式对其进行标记。有什么办法可以做到这一点吗?

amazon-s3 aws-开发工具包

评论


答:

10赞 Reza Mousavi 10/8/2018 #1

请尝试以下代码:

fields = {
    "x-amz-meta-u1": "value1",
    "x-amz-meta-u2": "value2"
}
conditions = [
    {"x-amz-meta-u1": "value1"},
    {"x-amz-meta-u2": "value2"}
]


presignedurl = s3_client.generate_presigned_post(
    bucket_name, "YOUR_BUCKET_NAME",
    Fields=copy.deepcopy(fields),
    Conditions=copy.deepcopy(conditions)
)

评论

1赞 deceze 10/8/2018
这似乎可以解决问题!为了澄清,我需要对字段和条件使用详细的 XML 标记集语法,这似乎可以根据需要工作。{'tagging': '...'}
1赞 Connor Wescott 1/29/2022 #2

Python 代码:

fields = {
    'tagging': '<Tagging><TagSet><Tag><Key>Foo</Key><Value>Bar</Value></Tag></TagSet></Tagging>',
}
conditions = [
    {'tagging': '<Tagging><TagSet><Tag><Key>Foo</Key><Value>Bar</Value></Tag></TagSet></Tagging>'}
]


presigned_url = s3_client.generate_presigned_post(
    Bucket="foo",
    Key="file/key.json",
    Fields=copy.deepcopy(fields),
    Conditions=copy.deepcopy(conditions)
)

CURL 命令:

$ curl -v --form-string "tagging=<Tagging><TagSet><Tag><Key>Foo</Key><Value>Bar</Value></Tag></TagSet></Tagging>" \
    -F key=file/key.json \
    -F x-amz-algorithm=... \
    -F x-amz-credential=... \
    -F x-amz-date=... \
    -F x-amz-security-token=... \
    -F policy=...\
    -F x-amz-signature=... \
    -F [email protected] \
    https://foo.s3.amazonaws.com/

解释

在 CURL 命令中使用这是必须的,否则 CURL 会将其解释为在文件中读取!--form-string=<

此外,请确保该目录位于当前工作目录中,以便 CURL 使用预签名 url 将文件上传到 S3。key.json