使用分段上传将文件放到Amazon S3

时间:2012-01-24 16:02:51

标签: java applet amazon-s3

我尝试通过分段上传来上传带有Amazon Java SDK的文件。我们的想法是将upload-id传递给applet,applet将文件部分放入readonly-bucket中。通过这种方式,我避免将AWS凭证存储在applet中。

在我的测试中,我使用boto(python)生成upload-id并将文件存储到存储桶中。这很有效。

我的Applet获得了#403; 403访问被拒绝"来自S3,我不知道为什么。

这是我的代码(部分取自http://docs.amazonwebservices.com/AmazonS3/latest/dev/llJavaUploadFile.html):

AmazonS3 s3Client = new AmazonS3Client();
List<PartETag> partETags = new ArrayList<PartETag>();

long contentLength = file.length();
long partSize = Config.getInstance().getInt("part_size");
String bucketName = Config.getInstance().getString("bucket");
String keyName = "mykey";
String uploadId = getParameter("upload_id");

try {
    long filePosition = 0;
    for (int i = 1; filePosition < contentLength; i++) {

        partSize = Math.min(partSize, (contentLength - filePosition));

        // Create request to upload a part.
        UploadPartRequest uploadRequest = new UploadPartRequest()
            .withBucketName(bucket).withKey(keyName)
            .withUploadId(uploadId).withPartNumber(i)
            .withFileOffset(filePosition)
            .withFile(file)
            .withPartSize(partSize);

        // Upload part and add response to our list.
        partETags.add(s3Client.uploadPart(uploadRequest).getPartETag());

        filePosition += partSize;
    }

    System.out.println("Completing upload");
    CompleteMultipartUploadRequest compRequest = new 
                CompleteMultipartUploadRequest(bucket, 
                                            keyName, 
                                            uploadId, 
                                            partETags);

    s3Client.completeMultipartUpload(compRequest);
} catch (Exception e) {
    s3Client.abortMultipartUpload(new AbortMultipartUploadRequest(
            bucketName, keyName, uploadId));
}

在applet调试日志中,我找到了这个,然后:

INFO: Sending Request: PUT https://mybucket.s3.amazonaws.com /mykey Parameters: (uploadId: V4hwobOLQ1rYof54zRW0pfk2EfhN7B0fpMJTOpHOcmaUl8k_ejSo_znPI540.lpO.ZO.bGjh.3cx8a12ZMODfA--, partNumber: 1, ) Headers: (Content-Length: 4288546, Content-Type: application/x-www-form-urlencoded; charset=utf-8, ) 
24.01.2012 16:48:42 com.amazonaws.http.AmazonHttpClient handleErrorResponse
INFO: Received error response: Status Code: 403, AWS Service: null, AWS Request ID: DECF32CCFEE9EBF0, AWS Error Code: AccessDenied, AWS Error Message: Access Denied, S3 Extended Request ID: xtL1ixsGM2/vsxJ+cZRHpkPZ23SMfP8hZZjQCQnp8oWGwdS2/aGfYgomihyqaDCQ

您是否在代码中发现任何明显的失败?

谢谢, 斯蒂芬

1 个答案:

答案 0 :(得分:7)

虽然你的用例是合理的,这确实是一个显而易见的尝试,但我认为Multipart Upload API的设计并不是为了实现这一点而你实际上是在违反安全屏障:

上传ID仅仅是一个标识符,用于协助 Multipart Upload API 将各部分组装在一起(即更像是临时对象密钥),而不是专用的安全机制(见下文)。因此,您仍然需要适当的访问凭据,但由于您正在调用AmazonS3Client(),其中构建将向Amazon S3发出匿名请求的新Amazon S3客户端,您的请求将产生 403拒绝访问

您可以通过Uploading Objects Using Pre-Signed URLs尝试实现的目标,但不幸的是,只有没有多部分功能:

  

预先签名的网址可让您访问网址中标识的对象,   前提是预签名URL的创建者具有权限   访问该对象。也就是说,如果您收到要上传的预签名网址   一个对象,只有在创建者时才能上传对象   预签名URL具有上传该对象的必要权限。

     

[...]预先签名的网址   如果您希望您的用户/客户能够上传特定内容,则非常有用   对象[...],但您不要求它们具有AWS安全性   凭据或权限。在创建预签名URL时,您必须这样做   提供您的安全凭证,指定一个桶名称对象   key,HTTP方法(上传对象的PUT)和到期日期   和时间。 [...]

长篇引语说明,为什么这样的可能这样的系统需要比“仅仅”分发上传ID更复杂的安全设计(类似于两者可能一见钟情)。

显然,人们希望能够同时使用这两种功能,但这似乎还没有。