Amazon S3 POST api,并使用 NodeJS 签署策略
Posted
技术标签:
【中文标题】Amazon S3 POST api,并使用 NodeJS 签署策略【英文标题】:Amazon S3 POST api, and signing a policy with NodeJS 【发布时间】:2013-08-30 20:05:15 【问题描述】:我正在尝试构建一个允许用户从 NodeJS 支持的网站将文件直接上传到我的 Amazon S3 存储桶的构建。似乎除了 the actual amazon docs for this 之外唯一的教程都已经过时了。
我一直在关注 this tutorial,了解基本信息,但它又过时了。它没有对 crypto
的方法调用正确,因为它试图将原始 javascript 对象传递给 update
方法,这会引发错误,因为它不是字符串或缓冲区。
我也一直在寻找 the knox npm package 的来源。它没有内置 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 生成带有签名的正确 Amazon S3 策略的工作教程,用于 POST 到 s3 REST api?
【问题讨论】:
将文件直接上传到 S3 并不是一件容易的事,尤其是如果你想支持分块、自动恢复、用户元数据等。策略的东西可以 相当复杂。考虑使用我维护的库:Fine Uploader。它原生支持在所有浏览器中直接上传到 S3,甚至是 IE7。除其他功能外,还支持分块和自动恢复。此外,我自己写了一个node.js server-side example,当与 Fine Uploader S3 配对时,它将为您处理所有签名。 您可以发表此评论作为答案吗?我最终可能会使用你的图书馆。仍在评估它是如何工作的,等等。 我不确定这是否会顺利进行。坦率地说,它可能被认为是一个糟糕的或仅链接的答案。我的理解是社区正在寻找包含代码的详细答案,而我的不符合该描述,这就是我将其发布为评论的原因。如果您对 Fine Uploader 有任何疑问,请查看 SO 上的 Fine-uploader 标签,我们会在其中处理库的支持问题。 @RayNicholus 我一直在研究使用 AWS 的“浏览器直接到 s3”上传,现在已经到了这个线程。我尝试过的两种方法是getSignedUrl()
,它非常简单,而这种形式的 POST 方法要复杂得多,但可配置性更高。我浏览了您的库,发现它使用了 s3 REST API,对吗?这和 Cognito 有什么关系吗?
【参考方案1】:
好吧,我终于想通了。在玩了很长时间的随机猜谜游戏后,我心想
“也许我需要签署 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);
;
希望这能帮助遇到同样问题的其他人。
【讨论】:
谢谢!这段代码帮助了我。一些快速的 cmets:格式化我使用的日期 moment.js 像这样: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 的示例,并且确实有效。所以我假设你的代码示例不再有效。【参考方案2】:
我修改了前面的示例,因为它对我不起作用:amazon 返回了一个关于损坏签名的错误。
以下是使用 POST(AWS 签名版本 4)为基于浏览器的上传创建签名的方法
http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-authentication-HTTPPOST.html
var CryptoJS = require("crypto-js");
var accessKeyID = "PUT YOUR DATA";
var secretAccessKey = "PUT YOUR DATA";
var bucket = "PUT YOUR BUCKET NAME";
var region = "eu-central-1"; // overwrite with your region
var folder = "users/"; // overwrite with your folder
var expiration = "2015-09-28T12:00:00.000Z"; // overwrite date
var date = "20150927"; // overwrite date
var serviceName = "s3";
function getSignatureKey(key, dateStamp, regionName, serviceName)
var kDate = CryptoJS.HmacSHA256(dateStamp, "AWS4" + key);
var kRegion = CryptoJS.HmacSHA256(regionName, kDate);
var kService = CryptoJS.HmacSHA256(serviceName, kRegion);
var kSigning = CryptoJS.HmacSHA256("aws4_request", kService);
return kSigning;
var s3Policy = "expiration": expiration,
"conditions": [
"bucket": bucket,
["starts-with", "$key", folder],
"acl": "public-read",
["starts-with", "$Content-Type", "image/"],
"x-amz-meta-uuid": "14365123651274",
["starts-with", "$x-amz-meta-tag", ""],
"x-amz-credential": accessKeyID + "/" + date + "/" + region + "/" + serviceName +"/aws4_request",
"x-amz-algorithm": "AWS4-HMAC-SHA256",
"x-amz-date": date + "T000000Z"
]
;
var base64Policy = new Buffer(JSON.stringify(s3Policy), "utf-8").toString("base64");
console.log('base64Policy:', base64Policy);
var signatureKey = getSignatureKey(secretAccessKey, date, region, serviceName);
var s3Signature = CryptoJS.HmacSHA256(base64Policy, signatureKey).toString(CryptoJS.enc.Hex);
console.log('s3Signature:', s3Signature);
接下来生成了我在上传表单中使用的 base64Policy 和 s3Signature。 示例在这里: http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html
非常重要的是检查您在 html 表单和策略中是否具有相同的字段和值。
【讨论】:
【参考方案3】:我仍然遇到问题,所以我解决了这些问题并在此处发布了我的解决方案:
https://github.com/nikkwong/ng2-s3-uploader
简而言之,如果您在构建签名时使用 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);
【讨论】:
【参考方案4】:AWS SDK 现在提供了一种使用 createPresignedPost()
创建 POST 策略的简单方法。
文档:https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#createPresignedPost-property
【讨论】:
以上是关于Amazon S3 POST api,并使用 NodeJS 签署策略的主要内容,如果未能解决你的问题,请参考以下文章
SignatureDoesNotMatch - Amazon S3 API
Amazon S3 CORS POST 因 JQuery-file-upload 失败
Amazon S3 - 不存在“Access-Control-Allow-Origin”标头
Amazon S3 对象存储Java API操作记录(Minio与S3 SDK两种实现)