不得不将AJAX上传到S3,但请求将返回SignatureDoesNotMatch
。在仔细检查访问密钥ID和密钥后,我对此问题感到茫然。我可以确认我确实也设置了CORS策略文件。
这是AJAX请求:
$.ajax({
url: 'https://my-bucket.s3.amazonaws.com/',
type: 'POST',
contentType: false,
data: formData,
success: function() {
self.unblockUI($('#body'));
},
error: function() {
self.unblockUI($('#body'));
},
cache: false,
processData: false
});
在Scala中执行我的策略编码/签名。这是代码:
val policy = """
|{"expiration": "2020-01-01T00:00:00Z",
|"conditions": [
|{"bucket": "my-bucket"},
|["starts-with", "$key", "uploads/"],
|{"acl": "public-read"},
|{"success_action_redirect": "http://example.com/"},
|["starts-with", "$Content-Type", ""],
|["starts-with","$Filename",""],
|["content-length-range", 0, 5242880]
|]
|}
""".stripMargin.stripLineEnd.replaceAll("\n", "").replaceAll("\r","")
val policyEncoded = (new BASE64Encoder()).encode(policy.getBytes("UTF-8")).stripLineEnd.replaceAll("\n", "").replaceAll("\r","")
val hmac = Mac.getInstance("HmacSHA1")
hmac.init(new SecretKeySpec(AWS_SECRET.getBytes("UTF-8"), "HmacSHA1"))
val policySignature = (new BASE64Encoder()).encode(hmac.doFinal(policy.getBytes("UTF-8"))).stripLineEnd.replaceAll("\n", "").replaceAll("\r","")
发送的表单如下:
------WebKitFormBoundaryTNKMpdRiJxhC39QF
Content-Disposition: form-data; name="key"
uploads/reward/img/example_02820838f08sd083k.jpeg
------WebKitFormBoundaryTNKMpdRiJxhC39QF
Content-Disposition: form-data; name="AWSAccessKeyId"
<redacted>
------WebKitFormBoundaryTNKMpdRiJxhC39QF
Content-Disposition: form-data; name="acl"
public-read
------WebKitFormBoundaryTNKMpdRiJxhC39QF
Content-Disposition: form-data; name="success_action_redirect"
http://example.com/
------WebKitFormBoundaryTNKMpdRiJxhC39QF
Content-Disposition: form-data; name="policy"
eyJleHBpcmF0aW9uIjogIjIwMjAtMDEtMDFUMDA6MDA6MDBaIiwiY29uZGl0aW9ucyI6IFsgeyJidWNrZXQiOiAicGxhdGZvcm0zLWNsaWVudC1pbWFnZXMifSwgWyJzdGFydHMtd2l0aCIsICIka2V5IiwgInVwbG9hZHMvIl0seyJhY2wiOiAicHVibGljLXJlYWQifSx7InN1Y2Nlc3NfYWN0aW9uX3JlZGlyZWN0IjogImh0dHA6Ly8za3Vkb3MuY29tLyJ9LFsic3RhcnRzLXdpdGgiLCAiJENvbnRlbnQtVHlwZSIsICIiXSxbInN0YXJ0cy13aXRoIiwiJEZpbGVuYW1lIiwiIl0sWyJjb250ZW50LWxlbmd0aC1yYW5nZSIsIDAsIDUyNDI4ODBdXX0gICAg
------WebKitFormBoundaryTNKMpdRiJxhC39QF
Content-Disposition: form-data; name="signature"
9jj1hW8pGpS32Ka4KA2R0MwYKTQ=
------WebKitFormBoundaryTNKMpdRiJxhC39QF
Content-Disposition: form-data; name="Content-Type"
image/jpeg
------WebKitFormBoundaryTNKMpdRiJxhC39QF
Content-Disposition: form-data; name="file"; filename="youtube_bg.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryTNKMpdRiJxhC39QF--
关于为什么失败的任何想法?我想我已经筋疲力尽了已知的可能性。谢谢!
答案 0 :(得分:4)
签名有一些问题,但其中一个是我没有编码正确的字符串。为了帮助不希望使用Amazon SDK的未来Scala用户,这里是我的Scala S3Policy
对象,它可以生成正确的签名。
注意:您不需要使用Play!记录器,除非您使用Play!框架;)
import play.api.Logger
import sun.misc.BASE64Encoder
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import com.codahale.jerkson.Json._
object S3Policy {
val AWS_ACCESS_KEY_ID = "<your access key ID goes here>"
val AWS_SECRET = "<your secret goes here>"
val AWS_ALGO = "HmacSHA1"
val policy = {
val policyMap = Map(
"expiration" -> "2014-01-01T12:00:00.000Z'",
"conditions" -> List(
Map("bucket" -> "<your bucket goes here>"),
Map("success_action_status" -> "201"),
Map("acl" -> "public-read"),
Array("starts-with", "$key", "uploads/"),
Array("starts-with", "$Content-Type", ""),
Array("starts-with", "$x-amz-meta-clientid", ""),
List("content-length-range", 0, 5242880)
)
)
val generated = generate(policyMap)
Logger.debug("AWS S3 POLICY: "+generated)
generated
}
val policyEncoded = (new BASE64Encoder()).encode(policy.getBytes("UTF-8")).replaceAll("\n", "").replaceAll("\r","")
val policySignature = signAndBase64Encode(policyEncoded, AWS_ALGO)
/**
* method to sign an AWS request
*/
def signAndBase64Encode(stringToSign: String, algo: String) = {
try {
val mac = Mac.getInstance(algo)
mac.init(new SecretKeySpec(AWS_SECRET.getBytes("UTF-8"), algo))
val signature = mac.doFinal(stringToSign.getBytes("UTF-8"))
val encoded = (new BASE64Encoder()).encode(signature)
Logger.debug("AWS S3 SIGNATURE: "+encoded)
encoded
} catch {
case e => Logger.error("Unable to calculate a request signature: " + e.getMessage(), e); "ERRORSTRINGNOTCALCULATED"
}
}
}
在上述政策中,您会注意到我使用的是x-amz-meta-
字段。如果您使用的是S3 metas,则需要以这种或那种方式定义。