英文:
SignatureDoesNotMatch on PutObject - Working on GetObject
问题
我正在尝试为S3中的putObject创建一个签名URL。我用于GetObject的方法运行良好,所以我的凭据是有效的。
我已经关闭了所有的公共访问权限,所以应该是公开可用的。
Bucket策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPutObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::adobe-sign-test/*"
}
]
}
Bucket CORS:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD",
"PUT"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
我尝试使用s3库和现在在这个示例中使用s3manager。但是当我尝试使用签名URL放置对象时,我收到一个XML错误,告诉我SignatureDoesNotMatch。
这是GET的工作代码和PUT的失败代码。
func getPresignedURL(bucket, key, operation string, expiresIn int64, region string, s3AccessKeyID string, s3SecretAccessKey string) string {
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String(region),
Credentials: credentials.NewStaticCredentials(
s3AccessKeyID,
s3SecretAccessKey,
"",
),
}))
uploader := s3manager.NewUploader(sess)
if operation == "PutObject" {
// 为PutObject操作生成预签名URL
uploadUrl, _ := uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
ACL: aws.String("bucket-owner-full-control"),
})
return uploadUrl.Location
}
// 为GetObject操作生成预签名URL
req, _ := uploader.S3.GetObjectRequest(&s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
getUrl, err := req.Presign(time.Duration(expiresIn) * time.Second)
if err != nil {
fmt.Println(err)
return ""
}
return getUrl
}
这是我如何使用curl PUT文件的方式:
curl -X PUT -T some-file.jpg "https://adobe-sign-test.s3.eu-north-1.amazonaws.com/hejsan.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAQJGLAAKTL3QQFZ73%2F20230706%2Feu-north-1%2Fs3%2Faws4_request&X-Amz-Date=20230706T074846Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=5eb429ee8efc1c8ffcae64d77a588119cfde81512bc5c4516a1120b20e26cac7"
这是put操作的错误消息:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>AKIAQJGLAAKTL3QQFZ73</AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256
20230706T074846Z
20230706/eu-north-1/s3/aws4_request
7666f6675cc3fe3a3aa20f98928aeccd4b9bc851666fcf03fb425d5819d7e72d</StringToSign><SignatureProvided>5eb429ee8efc1c8ffcae64d77a588119cfde81512bc5c4516a1120b20e26cac7</SignatureProvided><StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 32 33 30 37 30 36 54 30 37 34 38 34 36 5a 0a 32 30 32 33 30 37 30 36 2f 65 75 2d 6e 6f 72 74 68 2d 31 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 37 36 36 36 66 36 36 37 35 63 63 33 66 65 33 61 33 61 61 32 30 66 39 38 39 32 38 61 65 63 63 64 34 62 39 62 63 38 35 31 36 36 36 66 63 66 30 33 66 62 34 32 35 64 35 38 31 39 64 37 65 37 32 64</StringToSignBytes><CanonicalRequest>PUT
/hejsan.jpg
X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;X-Amz-Credential=AKIAQJGLAAKTL3QQFZ73%2F20230706%2Feu-north-1%2Fs3%2Faws4_request&amp;X-Amz-Date=20230706T074846Z&amp;X-Amz-Expires=3600&amp;X-Amz-SignedHeaders=host
host:adobe-sign-test.s3.eu-north-1.amazonaws.com
host
UNSIGNED-PAYLOAD</CanonicalRequest><CanonicalRequestBytes>50 55 54 0a 2f 68 65 6a 73 61 6e 2e 6a 70 67 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 51 4a 47 4c 41 41 4b 54 4c 33 51 51 46 5a 37 33 25 32 46 32 30 32 33 30 37 30 36 25 32 46 65 75 2d 6e 6f 72 74 68 2d 31 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 32 33 30 37 30 36 54 30 37 34 38 34 36 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 33 36 30 30 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 68 6f 73 74 0a 68 6f 73 74 3a 61 64 6f 62 65 2d 73 69 67 6e 2d 74 65 73 74 2e 73 33 2e 65 75 2d 6e 6f 72 74 68 2d 31 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 0a 68 6f 73 74 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes><RequestId>SMFDTR996NQE9DDV</RequestId><HostId>VehdLPGdnoVZclkNKs2+lTjFpAssA1Xe+HZSj5ZCCVK2QnumQHqzsePFg3TWWaai3+vqGgnwxpjMd3b8526I7Q==</HostId></Error>
英文:
I am trying to create a signed url for putObject in S3. My method for doing this for GetObject works fine, so my credentials are working.
I have turned off all blocks of public access so it should be publicly available.
Bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPutObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::adobe-sign-test/*"
}
]
}
Bucket CORS:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD",
"PUT"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
I have tried using both the s3 library and now in this example the s3manager. But when I try to put an object using the Signed URL I am receiving an XML error telling me the SignatureDoesNotMatch.
Here is the code for both the working GET, and the failing PUT.
func getPresignedURL(bucket, key, operation string, expiresIn int64, region string, s3AccessKeyID string, s3SecretAccessKey string) string {
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String(region),
Credentials: credentials.NewStaticCredentials(
s3AccessKeyID,
s3SecretAccessKey,
"",
),
}))
uploader := s3manager.NewUploader(sess)
if operation == "PutObject" {
// Generate a pre-signed URL for a PutObject operation
uploadUrl, _ := uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
ACL: aws.String("bucket-owner-full-control"),
})
return uploadUrl.Location
}
// Generate a pre-signed URL for a GetObject operation
req, _ := uploader.S3.GetObjectRequest(&s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
getUrl, err := req.Presign(time.Duration(expiresIn) * time.Second)
if err != nil {
fmt.Println(err)
return ""
}
return getUrl
}
Here is how I try to PUT a file using curl:
curl -X PUT -T some-file.jpg "https://adobe-sign-test.s3.eu-north-1.amazonaws.com/hejsan.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAQJGLAAKTL3QQFZ73%2F20230706%2Feu-north-1%2Fs3%2Faws4_request&X-Amz-Date=20230706T074846Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=5eb429ee8efc1c8ffcae64d77a588119cfde81512bc5c4516a1120b20e26cac7"
This is the error message for the put operation:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>AKIAQJGLAAKTL3QQFZ73</AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256
20230706T074846Z
20230706/eu-north-1/s3/aws4_request
7666f6675cc3fe3a3aa20f98928aeccd4b9bc851666fcf03fb425d5819d7e72d</StringToSign><SignatureProvided>5eb429ee8efc1c8ffcae64d77a588119cfde81512bc5c4516a1120b20e26cac7</SignatureProvided><StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 32 33 30 37 30 36 54 30 37 34 38 34 36 5a 0a 32 30 32 33 30 37 30 36 2f 65 75 2d 6e 6f 72 74 68 2d 31 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 37 36 36 36 66 36 36 37 35 63 63 33 66 65 33 61 33 61 61 32 30 66 39 38 39 32 38 61 65 63 63 64 34 62 39 62 63 38 35 31 36 36 36 66 63 66 30 33 66 62 34 32 35 64 35 38 31 39 64 37 65 37 32 64</StringToSignBytes><CanonicalRequest>PUT
/hejsan.jpg
X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;X-Amz-Credential=AKIAQJGLAAKTL3QQFZ73%2F20230706%2Feu-north-1%2Fs3%2Faws4_request&amp;X-Amz-Date=20230706T074846Z&amp;X-Amz-Expires=3600&amp;X-Amz-SignedHeaders=host
host:adobe-sign-test.s3.eu-north-1.amazonaws.com
host
UNSIGNED-PAYLOAD</CanonicalRequest><CanonicalRequestBytes>50 55 54 0a 2f 68 65 6a 73 61 6e 2e 6a 70 67 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 51 4a 47 4c 41 41 4b 54 4c 33 51 51 46 5a 37 33 25 32 46 32 30 32 33 30 37 30 36 25 32 46 65 75 2d 6e 6f 72 74 68 2d 31 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 32 33 30 37 30 36 54 30 37 34 38 34 36 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 33 36 30 30 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 68 6f 73 74 0a 68 6f 73 74 3a 61 64 6f 62 65 2d 73 69 67 6e 2d 74 65 73 74 2e 73 33 2e 65 75 2d 6e 6f 72 74 68 2d 31 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 0a 68 6f 73 74 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes><RequestId>SMFDTR996NQE9DDV</RequestId><HostId>VehdLPGdnoVZclkNKs2+lTjFpAssA1Xe+HZSj5ZCCVK2QnumQHqzsePFg3TWWaai3+vqGgnwxpjMd3b8526I7Q==</HostId></Error>
答案1
得分: 2
以下是您提供的代码的中文翻译:
在 AWS SDK Code Library for Go 中有一个示例,其中包含使用预签名URL进行S3的GET和PUT操作的示例,也许这可以帮到您。您可以克隆存储库并按照 README 中的说明自行运行这些示例。该示例包含了方法,然后有一个控制台应用程序来演示如何运行这些方法。
// GetObject 创建一个预签名请求,用于从存储桶中获取对象。
// 预签名请求在指定的秒数内有效。
func (presigner Presigner) GetObject(
bucketName string, objectKey string, lifetimeSecs int64) (*v4.PresignedHTTPRequest, error) {
request, err := presigner.PresignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
}, func(opts *s3.PresignOptions) {
opts.Expires = time.Duration(lifetimeSecs * int64(time.Second))
})
if err != nil {
log.Printf("无法获取用于获取 %v:%v 的预签名请求。原因:%v\n",
bucketName, objectKey, err)
}
return request, err
}
// PutObject 创建一个预签名请求,用于将对象放入存储桶中。
// 预签名请求在指定的秒数内有效。
func (presigner Presigner) PutObject(
bucketName string, objectKey string, lifetimeSecs int64) (*v4.PresignedHTTPRequest, error) {
request, err := presigner.PresignClient.PresignPutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
}, func(opts *s3.PresignOptions) {
opts.Expires = time.Duration(lifetimeSecs * int64(time.Second))
})
if err != nil {
log.Printf("无法获取用于放置 %v:%v 的预签名请求。原因:%v\n",
bucketName, objectKey, err)
}
return request, err
}
// DeleteObject 创建一个预签名请求,用于从存储桶中删除对象。
func (presigner Presigner) DeleteObject(bucketName string, objectKey string) (*v4.PresignedHTTPRequest, error) {
request, err := presigner.PresignClient.PresignDeleteObject(context.TODO(), &s3.DeleteObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
})
if err != nil {
log.Printf("无法获取用于删除对象 %v 的预签名请求。原因:%v\n", objectKey, err)
}
return request, err
}
您可以在此处找到更多关于此示例的信息。
英文:
There is an example in the AWS SDK Code Library for Go that has GET and PUT with presigned URLs for S3, maybe that will help. You can clone the repository and run these examples yourself following the instructions in the README. This sample has the methods and then there is a console application that demonstrates running them.
// GetObject makes a presigned request that can be used to get an object from a bucket.
// The presigned request is valid for the specified number of seconds.
func (presigner Presigner) GetObject(
bucketName string, objectKey string, lifetimeSecs int64) (*v4.PresignedHTTPRequest, error) {
request, err := presigner.PresignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
}, func(opts *s3.PresignOptions) {
opts.Expires = time.Duration(lifetimeSecs * int64(time.Second))
})
if err != nil {
log.Printf("Couldn't get a presigned request to get %v:%v. Here's why: %v\n",
bucketName, objectKey, err)
}
return request, err
}
// PutObject makes a presigned request that can be used to put an object in a bucket.
// The presigned request is valid for the specified number of seconds.
func (presigner Presigner) PutObject(
bucketName string, objectKey string, lifetimeSecs int64) (*v4.PresignedHTTPRequest, error) {
request, err := presigner.PresignClient.PresignPutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
}, func(opts *s3.PresignOptions) {
opts.Expires = time.Duration(lifetimeSecs * int64(time.Second))
})
if err != nil {
log.Printf("Couldn't get a presigned request to put %v:%v. Here's why: %v\n",
bucketName, objectKey, err)
}
return request, err
}
// DeleteObject makes a presigned request that can be used to delete an object from a bucket.
func (presigner Presigner) DeleteObject(bucketName string, objectKey string) (*v4.PresignedHTTPRequest, error) {
request, err := presigner.PresignClient.PresignDeleteObject(context.TODO(), &s3.DeleteObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
})
if err != nil {
log.Printf("Couldn't get a presigned request to delete object %v. Here's why: %v\n", objectKey, err)
}
return request, err
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论