如何使用预签名网址将对象放入亚马逊s3?

时间:2016-03-04 06:35:52

标签: javascript node.js amazon-web-services amazon-s3 pre-signed-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 我只能在设置以下选项时上传。我不明白如果只手动选择权限工作,使用存储桶策略是什么。

Permission for everyone

更新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}

5 个答案:

答案 0 :(得分:12)

我成功地使用您的代码上传了一个文件。

以下是我遵循的步骤:

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

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

    <activity
                android:name=".MainActivity"
                android:label="@string/app_name"
                android:launchMode="singleTask"
                android:screenOrientation="portrait"
                android:taskAffinity="com.mypage.app"
                android:theme="@style/AppTheme"
                android:windowSoftInputMode="adjustPan">
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
    
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.BROWSABLE" />
    
                    <data android:scheme="mypagemobileapp"/>
                    <data android:scheme = "http"
                        android:host="www.mypage.com"/>
                </intent-filter>
            </activity>
    
  3. 未创建存储桶策略

  4. 使用您的代码生成预签名网址:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "Stmt1418647210000",
                "Effect": "Allow",
                "Action": [
                    "s3:Put*"
                ],
                "Resource": [
                    "arn:aws:s3:::myBucket/*"
                ]
            }
        ]
    }
    
  5. 在屏幕上复制URL并使用curl测试上传,如下所示:

    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);
    });
    
  6. 在我的情况下,通常需要5-10秒才能使策略更改生效,因此如果第一次失败,请确保继续发送一段时间。

    希望这有帮助。

答案 1 :(得分:2)

您已正确设置存储桶的权限,以允许用户进行访问。

但您还需要编辑用户的策略,以允许用户访问S3服务。

编辑您用于生成自签名URL的凭据的用户的IAM策略。这样的事情肯定会涵盖一切:

{
  "Statement": [
    {
      "Sid": "AllowAllS3Access",
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

答案 2 :(得分:2)

  1. 在您的IAM控制台中,click Users
  2. 在右侧列表中,选择您使用的IAM用户(应该是&#39; myuser&#39;)
  3. 在子选项卡上选择权限
  4. 单击“附加策略”并选择“AmazonS3FullAccess”
  5. 最后一页将像this

    您还可以查看Security Credentials子选项卡,您的accessKeyId应该在列表中。 secretAccessKey再也无法恢复。

答案 3 :(得分:1)

它也可以帮到你:) 添加 ContentType 属性:

$exe = "C:\$var.exe"
Start-Process $exe -Verb runas

答案 4 :(得分:0)

这是在 S3 中为任何类型的文件生成预签名 URL 的完整代码。

  • 如果您愿意,可以在参数中使用 Expire 参数来包含到期时间。
  • 下面的代码将上传任何类型的文件,如 excel(xlsx, pdf, jpeg)

    const AWS = require('aws-sdk');
    const fs = require('fs');
    const axios = require('axios');
    const s3 = new AWS.S3();
    const filePath = 'C:/Users/siva.cheedella/Downloads/invoice.pdf';
    
    
    var params = {
        Bucket: 'testing-presigned-url-dev',
        Key: 'dummy.pdf',
        "ContentType": "application/octet-stream"
    };
    
    
    s3.getSignedUrl('putObject', params, function (err, url) {
        console.log('The URL is', url);
    
        fs.writeFileSync("./url.txt", url);
    
    
        axios({
            method: "put",
            url,
            data: fs.readFileSync(filePath),
            headers: {
                "Content-Type": "application/octet-stream"
            }
        })
            .then((result) => {
                console.log('result', result);
    
            }).catch((err) => {
                console.log('err', err);
    
            });
    
    });