提问者:小点点

签名不匹配:拒绝签名网址


我对使用 AWS S3 很陌生,并且正在尝试将图像上传到 S3,但遇到了臭名昭著的 SignatureDoesNotMatch 错误。我确保有任何拼写错误:(即键中的前导,尾随空格),检查我的系统时间是否关闭,但都无济于事。我的工作流程如下(如果您想参考,主要取自教程:https://medium.com/@diego.f.rodriguezh/direct-image-upload-to-aws-s3-with-react-and-express-2f063bc15430)。我尝试关注之前关于此问题的所有帖子,但仍然无法解决。

首先,在queries.js中,我处理URL的签名:

    accessKeyId: process.env.S3_KEY, // stored in the .env file
    secretAccessKey: process.env.S3_SECRET, // stored in the .env file
    region: process.env.BUCKET_REGION // This refers to your bucket configuration.
  });
// Creating a S3 instance
const s3 = new AWS.S3();

// Retrieving the bucket name from env variable
const Bucket = process.env.BUCKET_NAME; 
// PUT URL Generator
function generatePutUrl(Key, ContentType) {
  
  return new Promise((resolve, reject) => {
    // Note Bucket is retrieved from the env variable above.
    console.log('the key is:', Key)
    const params = { Bucket, ContentType, Expires:3600, Key };
        // Note operation in this case is putObject
    s3.getSignedUrl('putObject', params, function(err, url) {
      if (err) {
        console.log(err)
        reject(err);
      }
      // If there is no errors we can send back the pre-signed PUT URL
      resolve(url);
    });
  });
}

然后在index.js中:


// PUT URL
app.get('/generate-put-url', (req,res)=>{
  // Both Key and ContentType are defined in the client side.
  // Key refers to the remote name of the file.
  // ContentType refers to the MIME content type, in this case image/jpeg
  const { Key, ContentType } =  req.query;
  
  generatePutUrl(Key, ContentType).then(putURL => {
    console.log({putURL})
    res.send({putURL});
  })
  .catch(err => {
    res.send(err);
  });
});

app.listen(port, () => {
  console.log(`Listening on port ${port}`);
});

然后是我的组件uploader.js,它真正呈现了上传按钮,我在那里对签名的url发出get请求,然后我返回它对S3发出put请求:

getImage = e => {
    const files = e.target.files;
    if (files && files.length > 0) {
      const file = files[0];
      this.setState({ file });
    }
  };

  uploadFile = e => {
    
    e.preventDefault();
    const { file } = this.state;
    this.setState({message:'Uploading...'})
    const contentType = file.type; // eg. image/jpeg or image/svg+xml
    console.log(contentType)
    const generatePutUrl = 'http://localhost:4000/generate-put-url';
    const options = {
      params: {
        Key: file.name,
        ContentType: contentType,
      },
      headers: {
        'Content-Type': contentType
      }
    };
    
    axios.get(generatePutUrl, options).then(res => {
      const {
        data: { putURL }
      } = res;
      
      axios
        .put(putURL, file, options)
        .then(res => {
            
          this.setState({message:'Upload Successful'})
          setTimeout(()=>{
            this.setState({message:''});
            document.querySelector('#upload-image').value='';
          }, 2000)
        })
        .catch(err => {
          this.setState({message:'Sorry, something went wrong'})
          console.log('err', err);
        });
    });
  };

作为参考,我在输入放置请求之前记录了我的签名 URL,它看起来像这样(访问密钥 x-ed 输出)

putURL: 'https://polici-media.s3.us-east-2.amazonaws.com/32bitadder.JPG?Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIXXXXXXXXXXX%2F20200627%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20200627T050401Z&X-Amz-Expires=3600&X-Amz-Signature=d12f6228e20d3bc5fab2b38bd6e250992f3e362418eb8f61ed6c886a71eb46e7&X-Amz-SignedHeaders=host'

对于那些可能在教程中跟随的人来说,我真正改变的只是在后端使用端口3500到端口4000,但在这种情况下这不是问题。我也把这个URL放在邮递员中没有用,尽管URLhttps://polici-media.s3.us-east-2.amazonaws.com/32bitadder.JPG具有正确的标头和身份验证,在邮递员身上工作正常


共1个答案

匿名用户

通过从标题中删除内容类型来解决此问题。