我正在使用NodeJs将文件上传到AWS S3。我希望客户端能够安全地下载文件。所以我试图生成签名的URL,在一次使用后过期。我的代码看起来像这样:
上传
const s3bucket = new AWS.S3({
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
Bucket: 'my-bucket-name',
})
const uploadParams = {
Body: file.data,
Bucket: 'my-bucket-name',
ContentType: file.mimetype,
Key: `files/${file.name}`,
}
s3bucket.upload(uploadParams, function (err, data) {
// ...
})
下载
const url = s3bucket.getSignedUrl('getObject', {
Bucket: 'my-bucket-name',
Key: 'file-key',
Expires: 300,
})
问题
打开URL时,我得到以下内容:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>AccessDenied</Code>
<Message>
There were headers present in the request which were not signed
</Message>
<HeadersNotSigned>host</HeadersNotSigned>
<RequestId>D63C8ED4CD8F4E5F</RequestId>
<HostId>
9M0r2M3XkRU0JLn7cv5QN3S34G8mYZEy/v16c6JFRZSzDBa2UXaMLkHoyuN7YIt/LCPNnpQLmF4=
</HostId>
</Error>
我无法找到错误。我真的很感激任何帮助:)
您的代码是正确的,请仔细检查以下内容:
对于存储桶策略,您可以使用以下内容:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*"
}
]
}
使用您的桶名更改存储桶。
对于用户和访问密钥权限(#2),您应该按照以下步骤操作:
1-Goto AWS身份和访问管理(IAM),单击“策略”链接,然后单击“创建策略”按钮。
2 - 选择JSON选项卡。
3 - 输入以下语句,确保更改存储桶名称并单击“审核策略”按钮。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::YOURBUCKETNAME"
}
]
}
4 - 输入策略名称,然后单击“创建策略”按钮。
5 - 单击“用户”链接,找到您当前的用户名(您已拥有访问密钥和密码)
6-单击“添加权限”按钮。
7 - 添加我们在上一步中创建的策略并保存。
最后,确保您的存储桶无法从Public访问,将正确的内容类型添加到您的文件并设置signatureVersion: 'v4'
最终的代码应该是这样的,谢谢@Vaisakh PS:
const s3bucket = new AWS.S3({
signatureVersion: 'v4',
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
Bucket: 'my-bucket-name',
})
const uploadParams = {
Body: file.data,
Bucket: 'my-bucket-name',
ContentType: file.mimetype,
Key: `files/${file.name}`,
}
s3bucket.upload(uploadParams, function (err, data) {
// ...
})
const url = s3bucket.getSignedUrl('getObject', {
Bucket: 'my-bucket-name',
Key: 'file-key',
Expires: 300,
})
您的代码看起来不错,但我认为您在创建signatureVersion: 'v4'
对象时缺少s3bucket
参数。请尝试以下更新的代码。
const s3bucket = new AWS.S3({
signatureVersion: 'v4',
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
Bucket: 'my-bucket-name',
})
const uploadParams = {
Body: file.data,
Bucket: 'my-bucket-name',
ContentType: file.mimetype,
Key: `files/${file.name}`,
}
s3bucket.upload(uploadParams, function (err, data) {
// ...
})
const url = s3bucket.getSignedUrl('getObject', {
Bucket: 'my-bucket-name',
Key: 'file-key',
Expires: 300,
})
有关signatureVersion: 'v4'
的更多信息,请参阅以下链接
https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
您还可以尝试下面创建nodejs
的presigned url
库
我一直有类似的问题,但我的是由于地区设置。在我们的后端,我们为应用程序提供了一些配置设置。
其中一个是"region": "us-west-2"
所以预先设定的网址是用这个区域创建的,但是当它在前端被调用时,该区域被设置为"us-west-1"
。
改变它是固定的问题。