2013-05-07 53 views
1

试图将S3上传到AJAX,但请求返回的是SignatureDoesNotMatch。在重复检查访问密钥ID和秘密之后,我对这个问题感到不知所措。我可以确认我有,确实也设置CORS策略文件。亚马逊S3 SignatureDoesNotMatch在AJAX上传期间

这里的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 
      }); 

斯卡拉做我的政策编码/签名。下面的代码:

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-- 

任何想法,这是为什么失败?我想我已经用尽了已知的可能。谢谢!

回答

4

签名有一些问题,但其中一个是我没有编码正确的字符串。为了帮助那些不想使用亚马逊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,您需要定义这种或那种方式。

+0

您是否错过了该策略对象中的'generate'方法? – rtdp 2014-03-12 14:07:17

+0

'generate'来自Jerkson :) – crockpotveggies 2014-03-13 06:24:13