使用预先签署的网址将其放置到S3会产生403错误

hon*_*let 8 amazon-s3 http-status-code-403 angularjs pre-signed-url ng-file-upload

我正在使用Node来获取S3的presignedRUL以便将图像放入S3存储桶。

var aws = require('aws-sdk');
// Request presigned URL from S3
exports.S3presignedURL = function (req, res) {
  var s3 = new aws.S3();
  var params = {
    Bucket: process.env.S3_BUCKET, 
    Key: '123456', //TODO: creat unique S3 key
    //ACL:'public-read',
    ContentType: req.body['Content-Type'], //'image/jpg'
  };
  s3.getSignedUrl('putObject', params, function(err, url) {
      if(err) console.log(err);
      res.json({url: url});
  });
};
Run Code Online (Sandbox Code Playgroud)

这将成功检索以下形式的预签名网址:

https:// [my-bucket-name] .s3.amazonaws.com / 1233456?AWSAccessKeyId = [My-ID]&Expires = 1517063526&Signature = 95eA00KkJnJAgxdzNNafGJ6GRLc%3D (我必须包含过期标头吗?)

回到客户端(Web应用程序),我使用angular来生成HTTP请求。我曾经用过$ http和ngFileUpload,但都缺少类似的成功。这是我的ngFileUpload代码。

Upload.upload({
    url: responce.data.url, //S3 upload url including bucket name
    method: 'PUT',
    'Content-Type': file.type, //I have tried putting the ContentTyep header all over
    headers: { 
        //'x-amz-acl':'public-read',
        'Content-Type': file.type, 
    }, 
    data: { 
        file: file,
        headers:{'Content-Type': file.type,}
    },                         
})
Run Code Online (Sandbox Code Playgroud)

但是,似乎无论我如何格式化标题,总是会收到403错误。在错误的XML中说:

SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.
Run Code Online (Sandbox Code Playgroud)

我认为CORS不是问题。最初,我遇到了一些CORS错误,但它们看起来有所不同,我对S3存储桶CORS设置进行了一些更改,以使它们消失。对于presignedURL请求和对S3的PUT请求,我已经尝试了许多头的试验和错误设置,但是我似乎找不到正确的组合。

我确实注意到,当我console.log 403响应错误时,该字段

config.headers:{Content-Type: undefined, __setXHR_: ƒ, Accept: "application/json, text/plain, */*"}
Run Code Online (Sandbox Code Playgroud)

这是否表示未设置Content-Type头?当我将标头设置在我认为可能的所有位置时,怎么可能?无论如何,我的头撞在墙上有点了...


编辑:根据要求,我当前的CORS。(我投入了所有精力以摆脱之前的CORS警告。只有在上载成功后,我才会将其缩减为基本要求。)

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedOrigin>http://localhost:9500</AllowedOrigin>
    <AllowedOrigin>https://localhost:9500</AllowedOrigin>
    <AllowedOrigin>http://www.example.com</AllowedOrigin>
    <AllowedOrigin>https://www.example.com</AllowedOrigin>
    <AllowedOrigin>http://lvh.me:9500</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
    <AllowedHeader>Content-Type</AllowedHeader>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Run Code Online (Sandbox Code Playgroud)

小智 5

面临同样的问题。发现我用来创建预签名 URL 的内容类型与我发送到 S3 的对象的内容类型不匹配。我建议您在创建预签名 URL 时添加 Expiration 标头(我也这样做了),并在控制台中准确检查在您执行 S3 时发送的内容类型。此外,数据只需要是文件,而不是您在那里创建的结构。