2012-01-30 345 views
13

我使用curl调用Java ReST API来检索URL。然后,Java使用我的S3凭证为S3上传生成一个预先签名的URL,并在ReST回复中返回。 Curl获取URL并将其用于上传到S3,但S3返回403“我们计算的请求签名与您提供的签名不匹配,请检查您的密钥和签名方法。”使用预先签名的URL通过curl上传到s3(获得403)

这里是我使用生成签名的预URL代码:

public class S3Util { 
    static final AmazonS3 s3 = new AmazonS3Client(new AWSCredentials() { 
     @Override 
     public String getAWSAccessKeyId() { 
      return "XXXXXXX"; 
     } 
     @Override 
     public String getAWSSecretKey() { 
      return "XXXXXXXXXXXXXX"; 
     } 
    }); 
    static final String BUCKET = "XXXXXXXXXXXXXXXXXXXXXXXXXXX"; 

    static public URL getMediaChunkURL(MediaChunk mc, HttpMethod method) { 
     String key = ... 
     //way in the future (for testing)... 
     Date expiration = new Date(System.currentTimeMillis() + CalendarUtil.ONE_MINUTE_IN_MILLISECONDS*60*1000); 

     GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BUCKET, key, method); 
     req.setExpiration(expiration); 
     req.addRequestParameter("Content-Type", "application/octet-stream"); 

     //this gets passed to the end user: 
     return s3.generatePresignedUrl(req); 
    } 
} 

和卷曲,从庆典跑,我执行此:

echo Will try to upload chunk to ${location} 
curl -i -X POST \ 
     -F 'Content-Type=application/octet-stream' \ 
     -F "[email protected]${fileName}" \ 
     ${location} || (echo upload chunk failed. ; exit 1) 

除其他事项外,我试过PUT,而且我尝试过“Content-type”(小写字母T)。我意识到我错过了某些东西(或某些东西)显而易见,但是在阅读了相应的文档,使用Google搜索并查看了很多类似的问题后,我不确定这是什么。我看到很多关于需要的标题的提示,但我认为这个被拒绝的URL应该可以消除这些需求。也许不会?

TIA!

更新:

只是要清楚,我已经测试的下载,并且运行良好。

Java的样子:

GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BUCKET, key, HttpMethod.GET); 
req.setExpiration(expiration); 

和卷曲很简单:

curl -i ${location} 

回答

15

我已经能够产生通过C#预标识的URL,并上传后通过curl预期。由于我的测试中,我怀疑你是不是真的用卷曲正确 - 我已经能够上传文件,像这样:

curl -v --upload-file ${fileName} ${location} 

-v转储请求和响应头的参数(以及SSL握手)用于调试和说明目的:

> PUT [...] HTTP/1.1 
> User-Agent: curl/7.21.0 [...] 
> Host: [...] 
> Accept: */* 
> Content-Length: 12 
> Expect: 100-continue 

请注意,--upload-file(或-T)有利于PUT符合市场预期,但增加了更多的头部适当地产生回报作出恰当的回应:

< HTTP/1.1 100 Continue 
< HTTP/1.1 200 OK 
< x-amz-id-2: [...] 
< x-amz-request-id: [...] 
< Date: Tue, 31 Jan 2012 18:34:56 GMT 
< ETag: "253801c0d260f076b0d5db5b62c54824" 
< Content-Length: 0 
< Server: AmazonS3 
+0

感谢你。我坚持使用我的解决方案,因为我首先得到它,但我将其标记为正确,因为它解决了原始查询,并且,我认为它更好。 – 2012-01-31 20:30:14

+8

对我而言,预先签名的网址包含需要我用引号括住整个网址的字符。一旦我做到了,你的回答就完美了。 – 2014-03-17 21:52:07

+0

对我来说,使用POST预先签名的URL不起作用。只切换方法(在GeneratePresignedUrlRequest和curl中)解决了这个问题。 – 2017-01-28 16:01:23

-1

尽管GeneratePresignedUrlRequest接受的HTTP方法的参数(并具有setMethod功能),这似乎是不可用除GET之外

http://wiki.nercomp.org/wiki/images/0/05/AmazonWebServices.pdf国家“签署的请求,交给第三方执行的做法只适合简单的对象GET请求。”也许设置另一种方法可用于某些事情,但显然不是这样。

所以,相反,我在这里按照指示:

http://aws.amazon.com/articles/1434?_encoding=UTF8&jiveRedirect=1

这是比较复杂的,因为客户端需要发布一个完整的形式,而不是仅仅使用一个URL,并且还意味着所有发布的信息都必须单独传达给客户,但它确实有效。

+0

有趣的,我不知道这(前?)限制 - 它已被删除从这个主题的[当前文档](http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth),并且例如[PUT on S3:Problem](https://forums.aws.amazon.com/thread.jspa?messageID=262822񀊦)展示了使用'PUT'的一个显然有用的例子(尽管在那里讨论了侧面问题)。 – 2012-01-31 16:44:54

+0

我刚刚证实,使用PUT确实可以正常工作,正如预期的那样,通过C#生成预签名的URL,然后通过_curl_下载 - 我将在休息之后发布更多细节作为答案。 – 2012-01-31 18:29:42

+0

感谢您的跟进。 – 2012-01-31 20:28:25

4

当使用curl进行此操作时,您需要将url置于单引号中,否则会将半数查询字符串切掉(带有键/签名的部分)。

0

生成URL的方式:

private static URL generateRUL(String objectKey, String ACCESS_KEY, String SECRET_KEY, String BUCKET_NAME) { 
    AmazonS3 s3Client = new AmazonS3Client(new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY)); 
    URL url = null; 

    try { 
     GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(BUCKET_NAME, objectKey); 
     request.setMethod(com.amazonaws.HttpMethod.PUT); 
     request.setExpiration(new Date(System.currentTimeMillis() + (60 * 60 * 1000))); 

     // Very important ! It won't work without adding this! 
     // And request.addRequestParameter("Content-Type", "application/octet-stream") won't work neither 
     request.setContentType("application/octet-stream"); 

     url = s3Client.generatePresignedUrl(request); 
    } catch (AmazonServiceException exception) { 
    } catch (AmazonClientException ace) { } 

    return url; 
} 

上传文件的方式:

public int upload(byte[] fileBytes, URL url) { 
    HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 
    connection.setDoOutput(true); 
    connection.setRequestMethod("PUT"); 
    connection.setRequestProperty("Content-Type", "application/octet-stream"); // Very important ! It won't work without adding this! 
    OutputStream output = connection.getOutputStream(); 

    InputStream input = new ByteArrayInputStream(fileBytes); 
    byte[] buffer = new byte[4096]; 
    int length; 
    while ((length = input.read(buffer)) > 0) { 
     output.write(buffer, 0, length); 
    } 
    output.flush(); 

    return connection.getResponseCode(); 
} 
+0

request.setContentType(“application/octet-stream”);有用!我之前得到了403个禁止错误。我想知道它为什么起作用 – Jason 2017-07-24 02:17:07

相关问题