AWS S3 生成签名 URL ''AccessDenied''

新手上路,请多包涵

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

问题

打开网址时,我得到以下信息:

 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>

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

原文由 Flo 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

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

  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-转到 AWS 身份和访问管理 (IAM) 并单击策略链接并单击“创建策略”按钮。

在此处输入图像描述

2-选择 JSON 选项卡。

在此处输入图像描述

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

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

在此处输入图像描述

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

在此处输入图像描述

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

在此处输入图像描述

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

在此处输入图像描述

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

在此处输入图像描述

最后,确保您的存储桶无法从公共访问,将正确的内容类型添加到您的文件并设置 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,
})

原文由 Reza Mousavi 发布,翻译遵循 CC BY-SA 4.0 许可协议

这里最高赞的答案在技术上是可行的,但并不实用,因为它正在公开公开。

我有同样的问题,这是由于用于生成签名 url 的角色。我使用的角色是这样的:

 - Effect: Allow
  Action:
    - "s3:ListObjects"
    - "s3:GetObject"
    - "s3:GetObjectVersion"
    - "s3:PutObject"
  Resource:
    - "arn:aws:s3:::(bucket-name-here)"

但是只有桶名是不够的,我不得不在末尾添加一个通配符来指定对整个桶的访问:

 - Effect: Allow
  Action:
    - "s3:ListObjects"
    - "s3:GetObject"
    - "s3:GetObjectVersion"
    - "s3:PutObject"
  Resource:
    - "arn:aws:s3:::(bucket-name-here)/*"

原文由 Spencer Sutton 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题