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

Posted

技术标签:

【中文标题】如何使用预签名的 url 将对象放入 amazon s3?【英文标题】:How do I put object to amazon s3 using presigned url? 【发布时间】:2016-06-17 19:16:00 【问题描述】:

我正在尝试使用签名的 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

这是我的用户的政策:


  "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

【问题讨论】:

我假设 myAccessKeyId 和 mySecretAccessKey 都属于 myuser? 是的,他们属于用户 当你生成“myKey”的url时,你正在上传一个名为“myKey”的文件,对吧? @VolkanPaksoy 不一定。上传到 s3 后文件重命名为 myKey。问题不在于这里的文件名。问题是许可。当我将权限设置为所有人时文件上传,当我不设置时访问被拒绝;无论我的存储桶或用户政策如何 我明白了。我认为您不需要“委托人”是用户的策略,无论如何它都附加到该用户。我会尝试为该用户附加从列表中选择的完整 S3 访问策略,并尝试使用 CloudBerry 之类的工具上传带有他的密钥的文件,以避免对代码或手动策略的任何可能的疏忽。一旦您可以手动上传文件,我会尝试使用预签名的网址。 【参考方案1】:

这是在 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);
    
            );
    
    );

【讨论】:

【参考方案2】:

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

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

编辑您使用其凭证生成自签名 URL 的用户的 IAM 策略。此策略允许用户对账户中的所有 S3 存储桶进行完全管理访问:


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

【讨论】:

我还是不懂人。到底是怎么回事?它仍然给出拒绝访问错误。 这将授予用户对所有 S3 存储桶的所有权限。相当开放且不安全。 这授予用户在 S3 服务中执行任何操作的权限。它不会自动授予他们访问存储桶的权限,除非存储桶策略允许。【参考方案3】:

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

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

【讨论】:

我不知道为什么,但是在我添加这个之前我收到了签名错误! 上传时,您的浏览器会将内容类型添加到请求标头中。这将在执行的请求和您使用 getSignerUrl 获得的签名之间产生差异。当然,您必须根据要上传的文件设置正确的内容类型。【参考方案4】:

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

这是我遵循的步骤:

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

    如下设置 IAM 用户的策略:

    
        "Version": "2012-10-17",
        "Statement": [
            
                "Sid": "Stmt1418647210000",
                "Effect": "Allow",
                "Action": [
                    "s3:Put*"
                ],
                "Resource": [
                    "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);
    );
    

    复制屏幕上的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 秒才能生效,因此如果第一次失败,请确保继续发送一段时间。

希望这会有所帮助。

【讨论】:

您好,请问getSignedUrl函数中的myKey是什么。 @Siddhant 这基本上是 S3 上对象的名称。在此处查看参数说明:docs.aws.amazon.com/AWSjavascriptSDK/latest/AWS/… 我可以建议:- var s3 = new aws.S3( signatureVersion: 'v4', region: 'eu-central-1' ) - Key: 'images/upload/noek.jpg ' 我在这上面花了将近 3.5 个小时。拥有 apt-permission 集的 IAM 用户是完成此任务的正确方法。【参考方案5】:
    在您的 IAM 控制台中,click Users 在右侧列表中,选择您使用的 IAM 用户(应为“myuser”) 在子选项卡上选择权限 单击附加策略并选择 AmazonS3FullAccess

最后一页会像this。

您也可以检查安全凭证子选项卡,您的 accessKeyId 应该在列表中。 secretAccessKey 只是无法再次获取。

【讨论】:

它现在拥有完全的管理员权限。我可以从 s3 控制台上传。问题是我无法使用签名网址上传。

以上是关于如何使用预签名的 url 将对象放入 amazon s3?的主要内容,如果未能解决你的问题,请参考以下文章

使用预签名 URL 将文件上传到 Amazon S3 时出现 CORS 错误

如何使用 amazon sdk 为虚域生成预签名的 Amazon S3 url?

Alamofire 和预签名的 url 上传对象

放入 S3 预签名 URL 时如何修复“403 Forbidden”

Amazon S3 预签名 URL - 手动或一次性上传无效

Amazon s3 预签名 URL 受 IP 地址限制