Amazon S3 POST api и подписание политики с NodeJS
Я пытаюсь создать построенный, который позволяет пользователям загружать файл непосредственно в мой ковш Amazon S3 с веб-сайта NodeJS. Кажется, единственные учебные пособия, кроме фактических документов amazon для этого, очень устарели.
Я читал этот учебник, для получения базовой информации, но опять же это датировано. У него нет правильных вызовов метода crypto
, поскольку он пытается передать необработанный объект JavaScript методу update
, который выдает ошибку, потому что это не строка или буфер.
Я также смотрел источник пакета knox npm. У него нет встроенной поддержки POST, что я полностью понимаю, потому что браузер делает POST, когда у него есть правильные поля. Кажется, что у Knox есть правильный код для подписи политики, и я попытался заставить мой код работать на основе этого... но опять же безрезультатно.
Вот что я придумал для кода. Он создает политику с кодировкой base64 и создает подпись... но это неправильная подпись в соответствии с Amazon, когда я пытаюсь выполнить загрузку файла.
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);
};
Я, очевидно, что-то делаю неправильно. Но я понятия не имею, что. Может ли кто-нибудь помочь определить, что я делаю неправильно? Где моя проблема? Есть ли у кого-нибудь рабочий учебник для создания правильной политики Amazon S3 с сигнатурой от NodeJS v0.10.x для POST для s3 REST api?
Ответы
Ответ 1
Хорошо, я, наконец, понял это. После того, как я сыграл случайную игру догадки за ОЧЕНЬ долгое время, я подумал о себе
"возможно, мне нужно подписать закодированную base64 политику" - me
и 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);
};
Надеюсь, это поможет другим, которые столкнулись с той же проблемой.
Ответ 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);