如何使用预签名 url 将对象放入 amazon s3?

新手上路,请多包涵

我正在尝试使用签名 url 将图像上传到 s3 存储桶。以下是我的存储桶策略:

 {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::12345678:user/myuser",
                    "arn:aws:iam::12345678:root"
                ]
            },
        "Action": [
                "s3:List*",
                "s3:Put*",
                "s3:Get*"
            ],
            "Resource": [
                "arn:aws:s3:::myBucket",
                "arn:aws:s3:::myBucket/*"
            ]
        }
    ]
}

我正在从服务器生成签名的 url,如下所示:

 var aws = require('aws-sdk');
aws.config = {
    accessKeyId: myAccessKeyId,
    secretAccessKey: mySecretAccessKey
};

var s3 = new aws.s3();
s3.getSignedUrl('putObject', {
    Bucket: 'myBucket',
    Expires: 60*60,
    key: 'myKey'
}, function (err, url) {
    console.log(url);
});

我得到了网址。但是当我尝试放置一个对象时,出现以下错误:

 <Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>FXXXXXXXXX</RequestId>
    <HostId>fXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</HostId>
</Error>

更新 1

这是 myuser 的政策:

 {
  "Version": "2012-10-17",
  "Statement": [
    {
        "Sid": "",
        "Effect": "Allow",
        "Principal": {
            "AWS": [
                "arn:aws:iam::2xxxxxxxxxxx:user/myuser",
                "arn:aws:iam::2xxxxxxxxxxx:root"
            ]
        },
        "Action": [
            "s3:*"
        ],
        "Resource": [
            "arn:aws:s3:::myBucket",
            "arn:aws:s3:::myBucket/*"
        ]
    }
  ]
}

更新 2 我只能在设置以下选项时上传。如果仅手动选择权限工作,我不明白存储桶策略有什么用。

所有人的许可

更新 3

以下代码有效。现在唯一的问题是签名的网址

 #!/bin/bash

 file="$1"

 bucket="mybucket"
 resource="/${bucket}/${file}"
 contentType="image/png"
 dateValue=`date -R`
 stringToSign="PUT\n\n${contentType}\n${dateValue}\n${resource}"
 s3Key="AKxxxxxxxxxxxxxxxxx"
 s3Secret="/Wuxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
 signature=`echo -en ${stringToSign} | openssl sha1 -hmac ${s3Secret}     -binary | base64`
 curl -X PUT -T "${file}" \
   -H "Host: ${bucket}.s3.amazonaws.com" \
   -H "Date: ${dateValue}" \
   -H "Content-Type: ${contentType}" \
   -H "Authorization: AWS ${s3Key}:${signature}" \
   https://${bucket}.s3.amazonaws.com/${file}

原文由 Pravin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 904
2 个回答

我设法使用您的代码成功上传了文件。

以下是我遵循的步骤:

  1. 创建了一个新的存储桶和一个新的 IAM 用户

  2. 设置 IAM 用户的策略如下:

    {
       "Version": "2012-10-17",
       "Statement": [
           {
               "Sid": "Stmt1418647210000",
               "Effect": "Allow",
               "Action": [
                   "s3:Put*"
               ],
               "Resource": [
                   "arn:aws:s3:::myBucket/*"
               ]
           }
       ]
   }

  1. 没有创建存储桶策略

  2. 使用您的代码生成预签名 URL:

    var aws = require('aws-sdk');
   aws.config = {
       accessKeyId: myAccessKeyId,
       secretAccessKey: mySecretAccessKey
   };

   var s3 = new aws.s3();
   s3.getSignedUrl('putObject', {
       Bucket: 'myBucket',
       Expires: 60*60,
       Key: 'myKey',
       ContentType: 'image/jpeg',
   }, function (err, url) {
       console.log(url);
   });

  1. 复制屏幕上的 URL 并使用 curl 测试上传,如下所示:
    curl.exe -k -X PUT -T "someFile" "https://myBucket.s3.amazonaws.com/myKey?AWSAccessKeyId=ACCESS_KEY_ID&Expires=1457632663&Signature=Dhgp40j84yfjBS5v5qSNE4Q6l6U%3D"

在我的例子中,策略更改通常需要 5-10 秒才能生效,因此如果第一次失败,请确保继续发送一段时间。

_请注意_:如果您遇到 CORS 错误,请确保您已为 ContentType 调用提供了 s3.getSignedUrl 参数。正如 Hugo Mallet 在下面讨论的那样,“当你上传时,你的浏览器会将内容类型添加到请求标头中。[因此,如果你不提供 MediaType 服务器端,将会]执行的请求和您使用 getSignerUrl 获得的签名。当然,您必须根据要上传的文件设置正确的内容类型。”

原文由 Volkan Paksoy 发布,翻译遵循 CC BY-SA 4.0 许可协议

它也可能对您有帮助 :) 添加一个 ContentType 属性:

 s3.getSignedUrl('putObject', {
    Bucket: 'myBucket',
    Expires: 60*60,
    Key: 'myKey',
    ContentType: 'image/jpeg',
}, function (err, url) {
   console.log(url);
});

原文由 Hugo Mallet 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题