我可以按照步骤如本节所述生成预先签名的url,所以我想测试上传特定的图像marble.jpg
,并尝试使用postman
测试上传。因此,我复制了预先签名的url并使用一个endpoint
请求访问了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>
<Key>records/marble_cave.jpg</Key>
<BucketName>bucket</BucketName>
<Resource>/bucket/records/marble.jpg</Resource>
<RequestId>17E3999B521ABB65</RequestId>
<HostId>50abb07a-2ad0-4948-96e0-23403f661cba</HostId>
</Error>
设置了以下资源:
min.io
服务器进行本地测试。aws-sdk
版本3minio
creds,我肯定是在提出一个PUT
请求。因此,问题是:
signatureVersion
( getSignedUrl
用于在sdk的v3,import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
中生成预先签名的url )用于预先签名的url生成的代码是:
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
const s3Client = new S3Client({
region: 'us-east-1',
credentials: {
accessKeyId: 'minioadmin',
secretAccessKey: 'minioadmin',
},
endpoint: http://172.21.0.2:9000,
forcePathStyle: true,
});
const bucketParams = {
Bucket: 'myBucket',
Key: `marbles.jpg`,
};
const command = new PutObjectCommand(bucketParams);
const signedUrl = await getSignedUrl(s3Client, command, {
expiresIn: 10000,
})
发布于 2022-04-11 16:04:36
解决方案可能与我的其他问题中相同,因此只需复制答案:
我尝试并更改了端口,当我只使用本地主机进行url生成时,put
命令似乎可以工作。
因此,在上文中:
new S3Client({
region: 'us-east-1',
credentials: {
accessKeyId: 'minioadmin',
secretAccessKey: 'minioadmin',
},
endpoint: http://172.21.0.2:9000,
forcePathStyle: true,
});
我用:
new S3Client({
region: 'us-east-1',
credentials: {
accessKeyId: 'minioadmin',
secretAccessKey: 'minioadmin',
},
endpoint: http://172.21.0.2, // or 127.0.0.1
forcePathStyle: true,
});
注意,我没有使用任何端口号,所以默认情况是80
如果您使用的是docker-compose
,请添加此配置:
.
.
.
ports:
- 80:9000
而且效果很好。
发布于 2022-06-30 13:05:55
一年前,我偶然发现了这个问题,新的V3 SDK有一个bug,它在签署URL时没有考虑端口。见这里https://github.com/aws/aws-sdk-js-v3/issues/2726
我所做的工作最终实现了重写代码中的getSignedUrl
,并按如下方式添加了缺少的端口:
import {BuildMiddleware, MetadataBearer, RequestPresigningArguments} from '@aws-sdk/types';
import {Client, Command} from '@aws-sdk/smithy-client';
import {HttpRequest} from '@aws-sdk/protocol-http';
import {formatUrl} from '@aws-sdk/util-format-url';
import {S3RequestPresigner} from '@aws-sdk/s3-request-presigner';
export const getSignedUrl = async <
InputTypesUnion extends object,
InputType extends InputTypesUnion,
OutputType extends MetadataBearer = MetadataBearer
>(
client: Client<any, InputTypesUnion, MetadataBearer, any>,
command: Command<InputType, OutputType, any, InputTypesUnion, MetadataBearer>,
options: RequestPresigningArguments = {}
): Promise<string> => {
const s3Presigner = new S3RequestPresigner({ ...client.config });
const presignInterceptMiddleware: BuildMiddleware<InputTypesUnion, MetadataBearer> =
(next, context) => async (args) => {
const { request } = args;
if (!HttpRequest.isInstance(request)) {
throw new Error('Request to be presigned is not an valid HTTP request.');
}
// Retry information headers are not meaningful in presigned URLs
delete request.headers['amz-sdk-invocation-id'];
delete request.headers['amz-sdk-request'];
// User agent header would leak sensitive information
delete request.headers['x-amz-user-agent'];
delete request.headers['x-amz-content-sha256'];
delete request.query['x-id'];
if (request.port) {
request.headers['host'] = `${request.hostname}:${request.port}`;
}
const presigned = await s3Presigner.presign(request, {
...options,
signingRegion: options.signingRegion ?? context['signing_region'],
signingService: options.signingService ?? context['signing_service'],
});
return {
// Intercept the middleware stack by returning fake response
response: {},
output: {
$metadata: { httpStatusCode: 200 },
presigned,
},
} as any;
};
const middlewareName = 'presignInterceptMiddleware';
client.middlewareStack.addRelativeTo(presignInterceptMiddleware, {
name: middlewareName,
relation: 'before',
toMiddleware: 'awsAuthMiddleware',
override: true,
});
let presigned: HttpRequest;
try {
const output = await client.send(command);
//@ts-ignore the output is faked, so it's not actually OutputType
presigned = output.presigned;
} finally {
client.middlewareStack.remove(middlewareName);
}
return formatUrl(presigned);
};
https://stackoverflow.com/questions/71781531
复制相似问题