如何使用后端预签名网址使用SDK将文件上传到Amazon S3?

时间:2016-03-24 19:04:53

标签: javascript ruby-on-rails amazon-web-services amazon-s3 upload

我有一个Rails后端,它返回给我一个“签名”字符串,“objectKey”字符串和一个“策略”字符串。我必须使用这些参数来上传用户选择的文件,但我找不到任何方法来使用这些参数而不是使用Amazon JavaScript SDK的“accessKey”和“accessSecretKey”。

我已经有一个代码可以进行上传,但它直接使用了凭据,而且看起来并不安全。

任何人都已经遇到过这个问题?

2 个答案:

答案 0 :(得分:0)

您无法使用预先签名的网址上传对象。 AWS拥​​有解决方案,以便授予名为AWS Security Token Service的临时凭证。简称AWS STS。

Requesting Temporary Security Credentials - AWS Identity and Access Management

例如:

  1. 用户访问您的rails应用程序。
  2. 您的rails应用程序发出并使用AWS STS返回临时凭证。

    client = Aws::STS::Client.new
    policy = AWS::STS::Policy.new do |p|
      p.allow(
        actions: ['s3:PutObject'],
        resources: ['arn:aws:s3:::some-bucket/path/to/xxx*'],
        effect: 'allow'
      )
    end
    
    token = client.get_federation_token(name: 'name', policy: policy.to_json, duration_seconds: 900)
    puts token.credentials.to_json
    # {
    #   "access_key_id": "XXXXXXXXXXXXXXXXXXXX",
    #   "secret_access_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    #   "session_token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    #   "expiration": "2016-03-25T00:46:20Z"
    # }
    
  3. 用户使用临时凭证安全地上传对象。

  4. 请注意,当您使用临时凭证时,您必须使用access_key_id,secret_access_key和 session_token 进行身份验证。

答案 1 :(得分:0)

我没有找到解决我的AWS Sdk for JavaScript问题的解决方案。

在我们的案例中,看起来工作流程(签名/策略生成)与本文https://aws.amazon.com/articles/1434中显示的相同

为了解决这个问题,我将Sdk替换为一个简单的XmlHttpRequest和一个FormData对象,将我的文件推送到s3。无法更改有效负载以保持与应用程序的其他部分的兼容性。使用此方法,必须在formData中具有AccessKey,策略,签名,密钥(文件密钥)和文件。根据策略/签名的生成方式,还需要向formData添加其他字段以使事情正常工作。在这种情况下,我添加了一个sucess_action_status。

安装formData的代码:

  var formData = new FormData();
  formData.append('key', <KEY>);
  formData.append('AWSAccessKeyId', <ACCESS_KEY>);
  formData.append('policy', <POLICY>);
  formData.append('signature', <SIGNATURE>);
  formData.append('success_action_status', <SUCCESS_CODE>);
  formData.append('file', file, file.name);

使用此表单数据,像这样创建XMLHttpRequest

var request = new XMLHttpRequest();
request.open("POST","https://<YOUR BUCKET>.s3.amazonaws.com");
request.setRequestHeader("enctype", "multipart/form-data");

并发送传递formData对象的请求。

request.send(formData);

重要的是要记住formData中的值必须遵守生成的策略。

可以通过添加此Listener来获取上传过程:

request.upload.addEventListener('progress', function(e){
      console.log(e);
});

谢谢大家的帮助。