我有一个Play应用程序,需要将文件上传到S3。我们正在使用Scala进行开发并使用Java AWS开发工具包。
我在尝试上传文件时遇到问题,使用预签名的网址时,我一直收到403 SignatureDoesNotMatch。该URL使用AWS Java SDK通过以下代码生成:
def generatePresignedPutRequest(filename: String) = {
val expiration = new java.util.Date();
var msec = expiration.getTime() + 1000 * 60 * 60; // Add 1 hour.
expiration.setTime(msec);
s3 match {
case Some(s3) => s3.generatePresignedUrl(bucketname, filename, expiration, HttpMethod.PUT).toString
case None => {
Logger.warn("S3 is not availiable. Cannot generate PUT request.")
"URL not availiable"
}
}
}
对于前端代码,我们关注ioncannon文章。
上传文件的js函数(与文章中使用的函数相同)
function uploadToS3(file, url)
{
var xhr = createCORSRequest('PUT', url);
if (!xhr)
{
setProgress(0, 'CORS not supported');
}
else
{
xhr.onload = function()
{
if(xhr.status == 200)
{
setProgress(100, 'Upload completed.');
}
else
{
setProgress(0, 'Upload error: ' + xhr.status);
}
};
xhr.onerror = function()
{
setProgress(0, 'XHR error.');
};
xhr.upload.onprogress = function(e)
{
if (e.lengthComputable)
{
var percentLoaded = Math.round((e.loaded / e.total) * 100);
setProgress(percentLoaded, percentLoaded == 100 ? 'Finalizing.' : 'Uploading.');
}
};
xhr.setRequestHeader('Content-Type', 'image/png');
xhr.setRequestHeader('x-amz-acl', 'authenticated-read');
xhr.send(file);
}
}
服务器的响应是
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<StringToSignBytes>50 55 bla bla bla...</StringToSignBytes>
<RequestId>F7A8F1659DE5909C</RequestId>
<HostId>q+r+2T5K6mWHLKTZw0R9/jm22LyIfZFBTY8GEDznfmJwRxvaVJwPiu/hzUfuJWbW</HostId>
<StringToSign>PUT
image/png
1387565829
x-amz-acl:authenticated-read
/mybucketname/icons/f5430c16-32da-4315-837f-39a6cf9f47a1</StringToSign>
<AWSAccessKeyId>myaccesskey</AWSAccessKeyId></Error>
我已经配置了CORS,仔细检查了aws凭证并尝试更改请求标头。我总是得到相同的结果。为什么亚马逊告诉我签名不匹配?
怀疑OP仍然对此有问题,但是对于遇到此问题的其他人,这是答案:
向S3发出签名请求时,AWS检查以确保签名与浏览器发送的HTTP标头信息完全匹配。不幸的是,这是必读的:http : //s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html
但是,在上面的代码中实际上并非如此,JavaScript正在发送:
xhr.setRequestHeader('Content-Type', 'image/png');
xhr.setRequestHeader('x-amz-acl', 'authenticated-read');
但是在Java / Scala中,调用s3.generatePresignedUrl时不会传入任何一个。因此,生成的签名实际上是在告诉S3拒绝具有Content-Type或x-ams-acl标头集的任何内容。糟糕(我也喜欢)。
我见过浏览器会自动发送Content-Type,因此即使未明确将它们添加到标头中,它们仍可能会进入S3。所以问题是,如何将Content-Type和x-amz-acl标头添加到签名中?
AWS开发工具包中有几个重载的generatePresignedUrl函数,但是只有其中一个允许我们传递除存储桶名称,文件名,到期日期和http方法之外的其他任何内容。
解决方案是:
这是要使用的GeneratePresignedUrlRequest的正确函数定义:
AWS GitHub存储库上的函数代码对我来说也很有帮助,以了解如何对解决方案进行编码。希望这可以帮助。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句