Javascript AmazonS3发布api,并使用NodeJS签署策略

Javascript AmazonS3发布api,并使用NodeJS签署策略,javascript,node.js,amazon-web-services,amazon-s3,cryptography,Javascript,Node.js,Amazon Web Services,Amazon S3,Cryptography,我正在尝试建立一个允许用户直接上传文件到我的AmazonS3存储桶,从一个由NodeJS驱动的网站。除了之外,似乎仅有的教程都非常过时 我一直在关注,了解基本信息,但它又过时了。它没有对cryptocorrect的方法调用,因为它试图将原始JavaScript对象传递给update方法,该方法会抛出错误,因为它不是字符串或缓冲区 我还一直在查看的源代码。它没有内置的POST支持——我完全理解这一点,因为一旦它有了正确的字段,浏览器就可以完成POST。Knox似乎有正确的代码来签署策略,我已经尝试

我正在尝试建立一个允许用户直接上传文件到我的AmazonS3存储桶,从一个由NodeJS驱动的网站。除了之外,似乎仅有的教程都非常过时

我一直在关注,了解基本信息,但它又过时了。它没有对
crypto
correct的方法调用,因为它试图将原始JavaScript对象传递给
update
方法,该方法会抛出错误,因为它不是字符串或缓冲区

我还一直在查看的源代码。它没有内置的POST支持——我完全理解这一点,因为一旦它有了正确的字段,浏览器就可以完成POST。Knox似乎有正确的代码来签署策略,我已经尝试让我的代码基于此工作。。。但同样没有用

下面是我的代码。它生成base64编码策略,并创建签名。。。但亚马逊认为,当我尝试上传文件时,签名是错误的


var crypto = require("crypto");
var config = require("../../amazonConfig.json");

exports.createS3Policy = function(callback) {
  var date = new Date();

  var s3Policy = {
    "expiration": "2014-12-01T12:00:00.000Z",
    "conditions": [
      {"acl": "public-read"}, 
      ["content-length-range", 0, 2147483648],
      {"bucket": "signalleaf"}, 
      ["starts-with", "$Cache-Control", ""],
      ["starts-with", "$Content-Type", ""],
      ["starts-with", "$Content-Disposition", ""],
      ["starts-with", "$Content-Encoding", ""],
      ["starts-with", "$Expires", ""],
      ["starts-with", "$key", "/myfolder/"], 
      {"success_action_redirect": "http://example.com/uploadsuccess"},
    ]
  };

  var stringPolicy = JSON.stringify(s3Policy).toString("utf-8");
  var buffer = Buffer(stringPolicy, "utf-8");

  var encoded = buffer.toString("base64");
  var signature = crypto.createHmac("sha1", config.secretKey)
    .update(new Buffer(stringPolicy, "utf-8")).digest("base64");


  var s3Credentials = {
    s3PolicyBase64: encoded,
    s3Signature: signature
  };

  GLOBAL.s3creds = s3Credentials;

  callback(s3Credentials);
};


我显然做错了什么。但我不知道是什么。谁能帮我找出我做错了什么?我的问题在哪里是否有人提供了一个关于如何从NodeJS v0.10.x生成一个带有签名的AmazonS3策略的实用教程,用于发布到S3RESTAPI?

好的,我终于找到了答案。在玩了很长时间的随机猜测游戏后,我想

“也许我需要签署base64编码策略”-我

然后BAM就是这样

我还重新排序了条件,以匹配表单的发布方式,尽管我不确定这是否有什么不同

var crypto = require("crypto");
var config = require("../../amazonConfig.json");

exports.createS3Policy = function(contentType, callback) {
  var date = new Date();

  var s3Policy = {
    "expiration": "2014-12-01T12:00:00.000Z", // hard coded for testing
    "conditions": [
      ["starts-with", "$key", "somefolder/"], 
      {"bucket": "my-bucket-name"}, 
      {"acl": "public-read"}, 
      ["starts-with", "$Content-Type", contentType],
      {"success_action_redirect": "http://example.com/uploadsuccess"},
    ]
  };

  // stringify and encode the policy
  var stringPolicy = JSON.stringify(s3Policy);
  var base64Policy = Buffer(stringPolicy, "utf-8").toString("base64");

  // sign the base64 encoded policy
  var signature = crypto.createHmac("sha1", config.secretKey)
    .update(new Buffer(base64Policy, "utf-8")).digest("base64");

  // build the results object
  var s3Credentials = {
    s3Policy: base64Policy,
    s3Signature: signature
  };

  // send it back
  callback(s3Credentials);
};

希望这能帮助其他遇到同样问题的人。

我修改了前面的一个示例,因为它对我不起作用:amazon返回了一个关于签名损坏的错误

以下是如何使用POST(AWS签名版本4)为基于浏览器的上传创建签名

下一步生成的base64Policy和S3i签名用于上传表单。 例如:


非常重要的是检查html表单和策略中的字段和值是否相同。

我仍然存在问题,因此我解决了这些问题,并将解决方案发布在此处:

简言之,如果您在构建签名时使用scabbiaza的答案,请确保按照如下方式构建表单:

let formData = new FormData;
formData.append('acl', xAmzAcl);
formData.append('Content-Type', file.type);
formData.append('X-Amz-Date', xAmzDate);
formData.append('x-amz-server-side-encryption', xAmzServerSideEncryption);
formData.append('x-amz-meta-uuid', xAmzMetaUuid);
formData.append('X-Amz-Algorithm', xAmzAlgorithm);
formData.append('X-Amz-Credential', xAmzCredential);
formData.append('X-Amz-Signature', s3Signature);
formData.append('Policy', base64Policy);
formData.append('key', folder + '/' + file.name);
// File field must come last! 
formData.append('file', file);

AWS SDK现在提供了一种使用
createPresignedPost()
创建POST策略的简单方法


文档:

将文件直接上传到S3并不是一项简单的任务,特别是如果您希望支持分块、自动恢复、用户元数据等,那么策略内容可能会非常复杂。考虑使用我维护的库。它在所有浏览器(甚至IE7)中都支持直接上传到S3。除其他功能外,还支持分块和自动恢复。此外,我自己写了一篇文章,当与优秀的上传程序S3配对时,将为您处理所有签名。您能将此评论作为答案发布吗?我可能会用你的图书馆。仍在评估它的工作原理等,我不确定这是否会顺利进行。坦率地说,这可能被认为是一个糟糕的或仅限于链接的答案。我的理解是,社区正在寻找包含代码的详细答案,而我的答案不符合这一描述,这就是我将其作为评论发布的原因。如果您对Fine Uploader有任何疑问,请查看SO上的Fine Uploader标记,我们在那里处理库的支持问题。@RayNicholus我已经使用AWS研究了一段时间“browser direct to s3”上载,并到达了这个线程。我尝试过的两种方法是非常简单的
getSignedUrl()
,以及更复杂但更可配置的form POST方法。我浏览了一下您的lib,发现它使用了s3restapi,对吗?这跟Cognito有关系吗?谢谢!这个密码帮了我的忙。一些快速注释:将我使用的日期格式化如下:
moment.utc(expirationDate)。format('YYYY-MM-DD')+'T'+moment.utc(expirationDate)。format('HH:MM:ss.SSS')+'Z'
。另外,对于缓冲区,“utf8”(注意:没有连字符)是默认编码,所以我认为“utf-8”是不正确的和无关的。@Zugwalt,您可以使用moment的内置格式简化这一点
moment.utc(expirationDate).toISOString()
@Jonathan更好!谢谢不确定此项失败的原因,但我确实收到“我们计算的请求签名与您提供的签名不匹配。请检查您的密钥和签名方法。”错误。因此,我尝试使用@scabbiaza的例子,这个例子确实有效。因此,我假设您的代码示例不再有效。
let formData = new FormData;
formData.append('acl', xAmzAcl);
formData.append('Content-Type', file.type);
formData.append('X-Amz-Date', xAmzDate);
formData.append('x-amz-server-side-encryption', xAmzServerSideEncryption);
formData.append('x-amz-meta-uuid', xAmzMetaUuid);
formData.append('X-Amz-Algorithm', xAmzAlgorithm);
formData.append('X-Amz-Credential', xAmzCredential);
formData.append('X-Amz-Signature', s3Signature);
formData.append('Policy', base64Policy);
formData.append('key', folder + '/' + file.name);
// File field must come last! 
formData.append('file', file);