我正在尝试将文件从 Web 表单直接异步上传到 Amazon S3。为此,我必须验证客户端请求以在服务器上上传文件。
通过使用我的 AWS 密钥对上传请求进行数字签名,我可以创建一个经过身份验证的临时 URL,客户端可以使用该 URL 将文件上传到 S3 存储桶。
amazon S3 文档指定签名必须由以下生成
Signature = URL-Encode( Base64( HMAC-SHA1( YourSecretAccessKeyID,
UTF-8-Encoding-Of( StringToSign ) ) ) );
我在服务器上使用 Haskell,所以我的实现如下所示:
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Base64.Lazy as B64
import qualified Data.Digest.Pure.SHA as SHA
import qualified Data.ByteString.Lazy.Char8 as BL8
sign :: BL8.ByteString -> BL8.ByteString
sign = B64.encode . SHA.bytestringDigest . SHA.hmacSha1 secret
where secret = "aws-secret-key"
亚马逊文档的格式要求 StringToSign 看起来像:
StringToSign = HTTP-VERB + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Expires + "\n" +
CanonicalizedAmzHeaders +
CanonicalizedResource;
亚马逊的另一个例子:
GET\n
\n
\n
1175139620\n
/johnsmith/photos/puppy.jpg
所以我的字符串看起来像:
"PUT\n\n\n1384330538\n/bucketname/objname"
我签署了上面的字符串(使用 sign 函数)并制作了一个如下所示的 url:
https://s3.amazonaws.com/bucketname/objname?AWSAccessKeyId=accessskey&Signature=signature=&Expires=1384330979
然后在上传之前通过 AJAX 请求将其发送到客户端。我还更新了存储桶上的 CORS 策略以允许 PUT 请求。
问题是,每次我尝试使用上述签名的 url 上传内容时,我都会收到此消息(在 XML 文档中)。
我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。
所以我不确定我哪里出错了。注意:如果我使用公共 url ( https://s3.amazonaws.com/bucketname/objname ),我可以上传(但这不应该,我只希望用户上传 blob,而不是读取或删除等)