AWS S3生成签名的URL“AccessDenied”

问题描述 投票:0回答:3

我正在使用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>

我无法找到错误。我真的很感激任何帮助:)

node.js amazon-web-services amazon-s3 aws-sdk acl
3个回答
4
投票

您的代码是正确的,请仔细检查以下内容:

  1. 您的存储桶访问策略。
  2. 您的存储桶权限通过API密钥。
  3. 您的API密钥和秘密。
  4. 您的桶名称和密钥。

对于存储桶策略,您可以使用以下内容:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket/*"
        }
    ]
}

使用您的桶名更改存储桶。

对于用户和访问密钥权限(#2),您应该按照以下步骤操作:

1-Goto AWS身份和访问管理(IAM),单击“策略”链接,然后单击“创建策略”按钮。

enter image description here

2 - 选择JSON选项卡。

enter image description here

3 - 输入以下语句,确保更改存储桶名称并单击“审核策略”按钮。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::YOURBUCKETNAME"
        }
    ]
}

enter image description here

4 - 输入策略名称,然后单击“创建策略”按钮。

enter image description here

5 - 单击“用户”链接,找到您当前的用户名(您已拥有访问密钥和密码)

enter image description here

6-单击“添加权限”按钮。

enter image description here

7 - 添加我们在上一步中创建的策略并保存。

enter image description here

最后,确保您的存储桶无法从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,
})

1
投票

您的代码看起来不错,但我认为您在创建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

您还可以尝试下面创建nodejspresigned url

https://www.npmjs.com/package/aws-signature-v4


0
投票

我一直有类似的问题,但我的是由于地区设置。在我们的后端,我们为应用程序提供了一些配置设置。

其中一个是"region": "us-west-2"所以预先设定的网址是用这个区域创建的,但是当它在前端被调用时,该区域被设置为"us-west-1"

改变它是固定的问题。

© www.soinside.com 2019 - 2024. All rights reserved.