使用签名URL上传到S3时获取403(禁止)

使用签名URL上传到S3时获取403(禁止)

问题描述:

我试图生成预签名的URL,然后通过浏览器将文件上传到S3。我的服务器端代码如下所示,并生成以下URL:使用签名URL上传到S3时获取403(禁止)

let s3 = new aws.S3({ 
    // for dev purposes 
    accessKeyId: 'MY-ACCESS-KEY-ID', 
    secretAccessKey: 'MY-SECRET-ACCESS-KEY' 
}); 
let params = { 
    Bucket: 'reqlist-user-storage', 
    Key: req.body.fileName, 
    Expires: 60, 
    ContentType: req.body.fileType, 
    ACL: 'public-read' 
}; 
s3.getSignedUrl('putObject', params, (err, url) => { 
    if (err) return console.log(err); 
    res.json({ url: url }); 
}); 

这部分似乎正常工作。如果我登录它并将它传递到前端,我可以看到该URL。然后在前端,我试图用axios和签名的URL上传文件:

.then(res => { 
    var options = { headers: { 'Content-Type': fileType } }; 
    return axios.put(res.data.url, fileFromFileInput, options); 
    }).then(res => { 
    console.log(res); 
    }).catch(err => { 
    console.log(err); 
    }); 
} 

这样,我得到了403 Forbidden错误。如果我按照链接,有一些XML更多信息:

<Error> 
<Code>SignatureDoesNotMatch</Code> 
<Message> 
The request signature we calculated does not match the signature you provided. Check your key and signing method. 
</Message> 
...etc 

您的请求需要与签名完全匹配。一个显而易见的问题是,即使您将它包含在签名中,实际上您并没有在请求中包含预设的ACL。更改为:

var options = { headers: { 'Content-Type': fileType, 'x-amz-acl': 'public-read' } }; 
+0

谢谢,这不是,但我觉得我对问题的感觉更好。我很确定有些东西不匹配,我只是没有弄清楚究竟是什么。 – Alan

+1

虽然这应该是其中的一部分。这是一个非常确定性的过程,对不一致的容忍度为零。根据您实际发送的请求,错误消息中的CanonicalRequest将间接地告诉您应该将哪些参数传递给getSignedUrl()。 –

+0

谢谢,终于找到了正确的标题,并取得了成功的放入请求。 – Alan

1)您可能需要使用S3V4签名取决于如何将数据传输到AWS(对块流)。创建客户端如下:

var s3 = new AWS.S3({ 
    signatureVersion: 'v4' 
}); 

2)不要添加新标头或修改现有标头。该请求必须完全符合签名。

3)确保生成的url与发送给AWS的内容匹配。

4)做一个测试请求,在签名前删除这两行(并从你的PUT中删除头文件)。这将有助于缩小您的问题:

ContentType: req.body.fileType, 
    ACL: 'public-read' 
+0

谢谢,我跑过这个列表,我相信也许有一个标题不匹配。如何比较签名url中的标题和我发送的标题? – Alan

+0

你在调用getSignedUrl时在你的params中指定HTTP头。还要注意Michael sqlbot的回复x-amz-acl头。迈克尔的参数是正确的。确保你在你的PUT中包含相同的头文件。 –

+0

一个额外的项目。在签名和调用放入时,使用文件大小添加Content-Length。我没有看到指定的区域。创建客户端时添加此项。 –

有同样的问题,这里是你需要如何去解决它,

  1. 提取标识的URL的文件名部分。 执行打印,您正在使用查询字符串参数正确提取您的文件名部分。这很关键。
  2. 使用查询字符串参数编码到URI的文件名编码。
  3. 从编码文件名连同其他路径或从您的节点服务中返回您的lambda网址。

现在从axios与该网址发布,它将工作。

EDIT1: 如果您传递错误的内容类型,您的签名也将无效。

请确保您创建预签名url的内容类型与您正在使用它的内容类型相同。

希望它有帮助。

+0

谢谢,我给了这个尝试,但我不认为这是问题。该URL已经被正确编码了,如果我试图“重新编码”它,它实际上变成了一个死链接。 – Alan

+0

您能否确认您的内容类型与axios相同,然后创建了signedurl? – Kannaiyan