ruby 使用从STS临时凭证生成的预签名URL进行S3直接上载

7vhp5slm  于 2023-06-05  发布在  Ruby
关注(0)|答案(2)|浏览(326)

我正在尝试使用预签名的URL将文件上传到s3。我可以使用AssumeRole凭据成功生成URL,但从浏览器上传文件时,它抛出以下错误。

<Code>InvalidAccessKeyId</Code>
    <Message>The AWS Access Key Id you provided does not exist in our records.</Message>

方法一:

用于生成预签名URL的代码

cred = Aws::AssumeRoleCredentials.new(role_arn: ENV['AWS_ROLE_ARN'], role_session_name: 'xxx_service').credentials
post = Aws::S3::PresignedPost.new(creds, S3_REGION, S3_BUCKET, {
        key: Rails.env + '/' + file_name,
        metadata: {
          'original-filename' => file_name
        },
        acl: 'private',
      })

 url =  post.url,
 fields =  post.fields

从浏览器上传文件的前端代码

var form = new FormData();
form.append("key", "demo/test.xxx");
form.append("x-amz-meta-original-filename", "test.xxx");
form.append("policy", "XXXXXX");
form.append("x-amz-credential", "AXXXXXXX");
form.append("x-amz-algorithm", "AWS4-HMAC-SHA256");
form.append("x-amz-date", "20230530T145924Z");
form.append("x-amz-signature", "4XXXXXXXXXXXXXXX");
form.append("file", fileInput.files[0], "test.xxx");
form.append("x-amz-security-token", "IQXXXXXXXXXXX");

var settings = {
  "url": "https://bucket-url",
  "method": "POST",
  "timeout": 0,
  "processData": false,
  "mimeType": "multipart/form-data",
  "contentType": false,
  "data": form
};

$.ajax(settings).done(function (response) {
  console.log(response);
});

使用IAM用户凭据时也可以使用相同的代码。由于网络安全要求,我们已开始使用AssumeRole凭据。甚至我尝试在请求体中添加x-amz-session-token,但输出没有任何差异。
后来我发现了另一种生成预签名URL的方法,它允许我使用PUT方法从Brower成功上传文件。

方法二:

signer = Aws::S3::Presigner.new(credentails: creds, region: S3_REGION)
url, _ = signer.presigned_request(
            :put_object, bucket: S3_BUCKET, key: "#{Rails.env}/#{file_name}"
          )

从浏览器上传文件的前端代码

var form = new FormData();
form.append("file", fileInput.files[0], "test.xxx");

var settings = {
  "url": "https://bucket-url/demo/Sunspot.xxx?X-Amz-Algorithm=XXXXX&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Credential=XXXXX&X-Amz-Date=20230530T144029Z&X-Amz-Security-Token=XXXXX%3",
  "method": "PUT",
  "timeout": 0,
  "processData": false,
  "mimeType": "multipart/form-data",
  "contentType": false,
  "data": form
};

$.ajax(settings).done(function (response) {
  console.log(response);
});

上述解决方案的唯一问题是我无法从S3下载文件**.xxx后重新解析它。我已经通过上传PDF和PNG图像测试了这个解决方案,下载后它可以正常打开。也许S3在第二种方法中修改了文件.xxx**的签名/散列,因此我无法重新解析该文件。使用第一种方法和IAM凭据,它工作正常。
是否有其他方法可以不使用IAM用户凭据而直接从浏览器将文件上传到S3?

guykilcj

guykilcj1#

如果通过 reparse 你引用的文件再次从S3存储桶中获取它,我认为你需要使用预签名的URL来获取它:

client = ::Aws::S3::Resource.new(region: 'the-region')
bucket = client.bucket('the-bucket')
object = bucket.object('the-object-name-in-bucket')
filename = 'filename-as-to-be-downloaded'

presigned_url = object.presigned_url(
  :get, 
  expires_in: 300.seconds, 
  response_content_disposition: "attachment; filename=#{filename}"
)

然后,您只需从该URL获取文件,并根据需要对其进行转换。

UPDATE:使用ChunkyPNG按需转换镜像:

uri = URI.parse(presigned_url)
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = use_ssl
https.open_timeout = 5
https.ssl_timeout = 5

request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
downloaded = response.body

image = ChunkyPNG::Image.from_blob(downloaded)

300.seconds可能是特定于轨道的,我不确定您是否在使用,但这就是我们的想法。

nvbavucw

nvbavucw2#

我可以使用预签名POST机制本身上传文件。在前端代码中更改表单数据的顺序对我来说很有效。AWS错误消息具有误导性,它不是要求我们以正确的顺序发送安全字段,而是告诉我们AccessKEY未找到。我只是交换了x-amz-signaturex-amz-security-token的位置
工作码

var form = new FormData();
form.append("key", "demo/test.xxx");
form.append("x-amz-meta-original-filename", "test.xxx");
form.append("policy", "XXXXXX");
form.append("x-amz-credential", "AXXXXXXX");
form.append("x-amz-algorithm", "AWS4-HMAC-SHA256");
form.append("x-amz-date", "20230530T145924Z");
form.append("x-amz-signature", "4XXXXXXXXXXXXXXX");
form.append("file", fileInput.files[0], "test.xxx");
form.append("x-amz-security-token", "IQXXXXXXXXXXX");

var settings = {
  "url": "https://bucket-url",
  "method": "POST",
  "timeout": 0,
  "processData": false,
  "mimeType": "multipart/form-data",
  "contentType": false,
  "data": form
};

$.ajax(settings).done(function (response) {
  console.log(response);
});

我们需要在上传文件到S3时以正确的顺序发送安全字段。

  • x-amz算法
  • x-amz-credential
  • x-amz-date
  • 政策
  • x-amz安全令牌
  • x-amz签名

我从here找到了这个

相关问题