AWSS3GetPreSignedURLRequest 上传自定义 headers 给出 403

AWSS3GetPreSignedURLRequest upload with custom headers giving 403

我的 AWSS3GetPreSignedURLRequest 和 AFNetworking 的 NSMutableURLRequest 遇到了一些问题。我可以通过 Content-Type header 成功上传文件。但是,如果我添加 x-amz-aclx-amz-server-side-encryption,上传将失败并显示 403 - 无权限错误。我能做什么?这是亚马逊方面的问题,使用 server-side 加密或 ACL 不允许使用 pre-signed URL,或者更改请求是否有效?我非常深入地查看了 AWS 文档和 iOS SDK 参考,但对此一无所知。顺便说一下,我正在使用 AWS iOS SDK v2。有人知道怎么做吗?

    NSString *keyName;
    NSString *fileContentTypeStr;
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"MM.d.h.mm.ss"];
    if([multipleFileType isEqualToString:@"PNG"])
    {
        fileContentTypeStr = @"image/png";
        keyName = [NSString stringWithFormat:@"image_%@.png", [formatter stringFromDate:[NSDate date]]];
    }
    else if([multipleFileType isEqualToString:@"JPG"])
    {
        fileContentTypeStr = @"image/jpeg";
        keyName = [NSString stringWithFormat:@"image_%@.jpg", [formatter stringFromDate:[NSDate date]]];
    }
    self.imageUploadURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"image"]];

    [imageData writeToURL:self.imageUploadURL atomically:YES];
    AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = [AWSS3GetPreSignedURLRequest new];
    getPreSignedURLRequest.bucket = [NSString stringWithFormat:@"BUCKET-NAME/%@",  folderObject.objectId];
    getPreSignedURLRequest.key = keyName;
    getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodPUT;
    getPreSignedURLRequest.expires = [NSDate dateWithTimeIntervalSinceNow:3600];
    getPreSignedURLRequest.contentType = fileContentTypeStr;

    [[[AWSS3PreSignedURLBuilder defaultS3PreSignedURLBuilder] getPreSignedURL:getPreSignedURLRequest]
     continueWithBlock:^id(BFTask *task) {
         if (task.error) {
             NSLog(@"Error: %@",task.error);
         } else {
             NSURL *presignedURL = task.result;
             NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:presignedURL];
             [URLRequest setValue:fileContentTypeStr forHTTPHeaderField:@"Content-Type"];
             [URLRequest setValue:@"AES-256" forHTTPHeaderField:@"x-amz-server-side-encryption"];
             [URLRequest setValue:@"private" forHTTPHeaderField:@"x-amz-acl"];
             URLRequest.HTTPMethod = @"PUT";
             URLRequest.HTTPBody = imageData;

             AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
             NSProgress *progress;
             NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:URLRequest progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
             if(!error){
             NSLog(@"File was successfully uploaded.");
             }
             }];
             [uploadTask resume];
         }
         return nil;
     }];

注意:那里的代码示例缺少一些全局 headers 上的东西,以及一些其他完成块 + 委托,但我相信每个人都会明白这里的要点。

期待感谢,

我们将 - setValue:forRequestParameter: 添加到 AWSS3GetPreSignedURLRequest。您可以使用此方法添加 ACL 和加密 headers.

此外,我们引入了一个新的 AWSS3TransferUtility 来简化后台传输。请参阅我们的blog post了解更多详情。

正如@YosukeMatsuda 在评论中注意到的那样,您可以使用 putObjectAcl: 方法。

我将上传对象的 ACL 放在 URLSession didCompleteWithError 上:委托方法如下:

//
self.awss3 = [[AWSS3 alloc] initWithConfiguration:__your_config__];
//

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    if (error)
    {
        NSLog(@"S3 UploadTask: %@ completed with error: %@", task, [error localizedDescription]);
    }
    else
    {
//      AWSS3GetPreSignedURLRequest does not contain ACL property, so it has to be set after file was uploaded to bucket
        AWSS3PutObjectAclRequest *aclRequest = [AWSS3PutObjectAclRequest new];
        aclRequest.bucket = @"your_bucket";
        aclRequest.key = @"your_key";
        aclRequest.ACL = AWSS3ObjectCannedACLPublicRead;

        [[self.awss3 putObjectAcl:aclRequest] continueWithBlock:^id(BFTask *bftask) {
            if (bftask.error)
            {
                NSLog(@"Error putObjectAcl: %@", [bftask.error localizedDescription]);
            }
            else
            {
                AWSEndpoint *endpoint =  self.awss3.configuration.endpoint;
                NSURL *publicReadURL = [[endpoint.URL URLByAppendingPathComponent:backgroundUploadTask.bucket] URLByAppendingPathComponent:backgroundUploadTask.key];
            }
            return nil;
        }];
    }
}