簡體   English   中英

使用預先簽名的URL上傳到帶有curl的s3(獲得403)

[英]Upload to s3 with curl using pre-signed URL (getting 403)

我正在使用curl調用Java ReST API來檢索URL。 然后,Java使用我的S3憑據生成用於S3上載的預簽名URL,並在ReST回復中返回該URL。 Curl獲取URL並使用它上傳到S3,但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);
    }
}

在curl中,從bash運行,我執行這個:

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

除此之外,我嘗試了PUT,我嘗試過“內容類型”(小寫T)。 我意識到我錯過了一些顯而易見的東西(或者某些東西),但在閱讀了相應的文檔,谷歌搜索並查看了許多類似的問題后,我不確定那是什么。 我看到很多關於必需標題的提示,但我認為重新簽名的URL應該可以消除這些需求。 也許不吧?

TIA!

更新:

為了清楚起見,我測試了下載,這很好。

Java看起來像:

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

和卷曲簡單地說:

curl -i ${location}

我已經能夠通過C#生成預先簽名的URL,然后按預期通過curl上傳。 鑒於我的測試我懷疑你確實沒有正確使用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

當使用curl執行此操作時,您需要將url放在單引號中,否則查詢字符串的一半會被切斷(帶有鍵/簽名的部分)。

生成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();
}

盡管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,並且還意味着所有帖子信息必須單獨傳遞給客戶端,但它似乎確實有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM