微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用预签名 URL (S3 Amazon) 通过 JS 将文件上传到 AWS 存储桶时出现 403 禁止错误

如何解决使用预签名 URL (S3 Amazon) 通过 JS 将文件上传到 AWS 存储桶时出现 403 禁止错误

我在使用预签名 URL 将文件上传到 AWS 中的 S3 存储桶时遇到问题。我通过服务器端生成 URL,将其发送到客户端,然后客户端通过 JS 发出 HTTP 上传请求。

这是我的场景:

我在 AWS 管理控制台中设置了一个客户端,我在服务器端为 S3 服务打开了一个实例,并使用了正确的凭证和配置:

@Bean
public AmazonS3 getS3Client() {
        
    AWSCredentials credentials = new BasicAWSCredentials(accessKey,secretKey);
    return AmazonS3ClientBuilder.standard().withCredentials(
        new AWsstaticCredentialsProvider(credentials))
        .withRegion(region).build();
}

然后我通过指定 CORS 角色的服务器创建一个存储桶:

s3Client.createBucket(new CreateBucketRequest(bucketName,s3Config.getRegion()));
                
List<CORSRule.AllowedMethods> rule1AM = new LinkedList();
rule1AM.add(CORSRule.AllowedMethods.PUT);
rule1AM.add(CORSRule.AllowedMethods.POST);
CORSRule rule1 = new CORSRule().withId("CORSRule1").withAllowedMethods(rule1AM)
                        .withAllowedOrigins(Arrays.asList(ServletUriComponentsBuilder.fromCurrentcontextpath().toUriString()));
                
List<CORSRule> rules = new LinkedList();
rules.add(rule1);
BucketCrossOriginConfiguration configuration = new BucketCrossOriginConfiguration();
configuration.setRules(rules);
                
s3Client.setBucketCrossOriginConfiguration(bucketName,configuration);

AWS 中的 Bucket 创建成功,包含的权限如下所示:

[
    {
        "AllowedHeaders": [],"AllowedMethods": [
            "PUT","POST"
        ],"AllowedOrigins": [
            "http://localhost:8080"
        ],"ExposeHeaders": []
    }
]

此外,在配置范围内,我在我的 IAM 中设置了一个策略和角色来上传 Pourpose。 政策:

{
    "Version": "2012-10-17","Statement": [
        {
            "Sid": "VisualEditor0","Effect": "Allow","Action": [
                "s3:PutObject","s3:Getobject"
            ],"Resource": "arn:aws:s3:::*/*"
        }
    ]
}

;以及使用该政策的角色。

这就是配置部分的全部内容。至于上传功能,我使用服务器端和客户端。客户端发送对预签名 URL 的请求,该请求是通过服务器生成的。然后我在 JS 中通过 Ajax 打开一个 POST 请求,使用接收到的 URL 发送文件

服务端的Pre-Signed URL生成方法,提供bucketName、filename和文件类型:

java.util.Date expiration = new java.util.Date();
long expTimeMillis = Instant.Now().toEpochMilli();
expTimeMillis += 1000 * 60 * 60;
expiration.setTime(expTimeMillis);
            
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName,URLEncoder.encode(filename,"UTF-8"))
               .withMethod(HttpMethod.POST)
               .withExpiration(expiration)
               .withContentType(type);
            
URL url = s3Client.generatePresignedUrl(request);
            
return url.toString();

生成的网址如下:

https://[...].s3.sa-east-1.amazonaws.com/[filename]?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20210731T155449Z&X-Amz-SignedHeaders =content-type%3Bhost&X-Amz-Expires=3599&X-Amz-Credential=[...]&X-Amz-Signature=[...]

至于最后一步,我创建了在客户端上传文件的请求:

try {
    // Variables to calculate upload speed
    var uploaded = 0;
    var upSpeed = 0;
    var lastUpTime = 0;
    
    // Creates the HTTP request for the upload
    $.ajax({
        url: url,type: "POST",data: file,processData: false,contentType: file.type,timeout: 0,xhr: function() {
            var xhr = new window.XMLHttpRequest();
            xhr.upload.addEventListener("progress",function (evt) {
                if (evt.lengthComputable) {
                    if (serverProgressDone === false) {
                        // Calculates the speed and progress
                        [...]
                    } 
                }
            },false);
            return xhr;
        },success: function(result) {
            console.log('upload finished sucessfully!');
        },error: function (jqXHR,textStatus,errorThrown) {
            console.log('XHR Error: ' + errorThrown);
        }
    });
} catch (e) {
    console.log('Exception Error: ' + e);
}

问题是我总是收到带有 SignatureDoesNotMatch 消息的 403 禁止回复。但是,由于我使用现有的 s3Client 凭据通过服务器生成预签名 URL(效果很好,因为我仅通过服务器端成功地将内容上传和下载到存储桶),我不知道怎么会有签名不匹配。最初我也遇到了 CORS 错误,但由于我在创建存储桶时配置了存储桶权限,包括 CORS 规则,因此似乎已解决

错误一个奇怪方面是当我打开 XML 响应时,其中包含规范请求标记,并且它的值以 GET 开头,在我的理解中应该是 POST。

如果有人能阐明此事,将不胜感激!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。