如何解决使用预签名 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 举报,一经查实,本站将立刻删除。