18

Tôi đang cố gắng để có được một xây dựng cho phép người dùng tải lên một tập tin trực tiếp vào thùng Amazon S3 của tôi, từ một trang web hỗ trợ NodeJS. Dường như các hướng dẫn duy nhất ở ngoài kia, ngoài the actual amazon docs for this đều hết hạn.Amazon S3 POST api, và ký một chính sách với NodeJS

Tôi đã theo dõi this tutorial, để biết thông tin cơ bản, nhưng lại xuất hiện. Nó không có phương thức gọi tới crypto chính xác, vì nó cố gắng truyền một đối tượng JavaScript thô đến phương thức update, mà ném một lỗi vì nó không phải là một chuỗi hoặc bộ đệm.

Tôi cũng đã xem mã nguồn cho the knox npm package. Nó không có hỗ trợ POST được xây dựng - mà tôi hoàn toàn hiểu, bởi vì nó là trình duyệt đang thực hiện POST khi nó có đúng trường. Knox dường như có mã đúng để ký một chính sách, và tôi đã cố gắng làm cho mã của tôi hoạt động dựa trên điều này ... nhưng lại không có kết quả.

Đây là những gì tôi đã đưa ra, cho mã. Nó tạo ra một chính sách mã hóa base64, và nó tạo ra một chữ ký ... nhưng đó là chữ ký sai theo Amazon, khi tôi cố gắng thực hiện tải lên tệp.


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); 
}; 

Tôi rõ ràng đang làm điều gì đó sai, ở đây. Nhưng tôi không có ý tưởng gì. Bất cứ ai có thể giúp xác định những gì tôi đang làm sai? Vấn đề của tôi ở đâu? Có ai có hướng dẫn làm việc về cách tạo một Chính sách Amazon S3 phù hợp không, với chữ ký, từ NodeJS v0.10.x, cho một POST tới s3 REST api?

+1

Tải tệp trực tiếp lên S3 không thực sự là một nhiệm vụ tầm thường, đặc biệt nếu bạn muốn hỗ trợ chunking, tự động tiếp tục, siêu dữ liệu người dùng, v.v ... Xem xét sử dụng thư viện mà tôi duy trì: [Trình tải lên tốt] (http://fineuploader.com). Nó có hỗ trợ bản địa để tải lên trực tiếp lên S3 trong tất cả các trình duyệt, ngay cả IE7. Chunking và tự động tiếp tục, trong số các tính năng khác, cũng được hỗ trợ. Hơn nữa, tôi đã tự viết [ví dụ phía máy chủ node.js] (http://bit.ly/1do27a0) rằng, khi được ghép nối với Fine Uploader S3, sẽ xử lý tất cả chữ ký cho bạn. –

+0

bạn có thể đăng nhận xét này làm câu trả lời không? tôi có thể sẽ sử dụng thư viện của bạn. vẫn đang đánh giá nó hoạt động như thế nào, v.v. –

+1

Tôi không chắc chắn nó sẽ tiến triển tốt như thế nào. Nó có thể được coi là một câu trả lời nghèo hoặc liên kết, khá thẳng thắn. Sự hiểu biết của tôi là cộng đồng đang tìm kiếm các câu trả lời chi tiết bao gồm mã, và tôi không phù hợp với mô tả đó, đó là lý do tại sao tôi đăng nó như một bình luận. Nếu bạn có bất kỳ câu hỏi nào về Trình tải lên Tốt, hãy xem thẻ trình tải lên tốt trên SO, trong đó chúng tôi xử lý các câu hỏi hỗ trợ cho thư viện. –

Trả lời

34

Ok, cuối cùng tôi đã tìm ra. Sau khi chơi trò chơi đoán ngẫu nhiên trong một thời gian rất lâu, tôi tự nghĩ

"có lẽ tôi cần phải ký vào base64 chính sách mã hóa" - tôi

BAM đó là nó.

Tôi cũng đã đặt hàng lại các điều kiện để khớp với cách biểu mẫu đăng, mặc dù tôi không chắc chắn điều này tạo nên sự khác biệt.

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); 
}; 

Hy vọng điều này sẽ giúp những người khác chạy đến cùng một vấn đề.

+0

CẢM ƠN BẠN! Mã này đã giúp tôi. Một số nhận xét nhanh: Để định dạng ngày tôi đã sử dụng [moment.js] (http://momentjs.com/docs/) như sau: 'moment.utc (expirationDate) .format ('YYYY-MM-DD') + ' T '+ moment.utc (expirationDate) .format (' HH: mm: ss.SSS ') +' Z''. Ngoài ra cho bộ đệm 'utf8' (lưu ý: không có dấu nối) là mã hóa mặc định vì vậy tôi nghĩ rằng "utf-8" là không chính xác và không liên quan. – Zugwalt

+4

@Zugwalt, bạn có thể đơn giản hóa điều đó một chút với định dạng dựng sẵn của thời điểm. 'moment.utc (expirationDate) .toISOString()' – Jonathan

+0

@ Jonathan thậm chí còn tốt hơn! Cảm ơn! – Zugwalt

14

Tôi đã sửa đổi ví dụ trước một chút, vì nó không hoạt động đối với tôi: amazon trả lại lỗi về chữ ký bị hỏng.

Sau đây là cách chữ ký nên được tạo ra đối với Tải trình duyệt dựa trên Sử dụng POST (AWS Chữ ký Version 4)

http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-authentication-HTTPPOST.html

Calculating a Signature

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); 

Tiếp theo tạo base64Policy và s3Signature tôi được sử dụng trong biểu mẫu để tải lên. Ví dụ ở đây: http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html

Điều quan trọng là phải kiểm tra xem bạn có cùng trường và giá trị trong biểu mẫu html và trong chính sách của mình hay không.

1

Tôi tiếp tục có vấn đề, vì vậy tôi làm việc qua chúng và gửi giải pháp của tôi ở đây:

https://github.com/nikkwong/ng2-s3-uploader

Nói tóm lại, nếu bạn đi với câu trả lời scabbiaza trong việc xây dựng chữ ký, hãy chắc chắn để xây dựng các hình thức như vậy:

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); 
+0

Dữ liệu biểu mẫu của bạn không bao gồm "x-amz-meta-tag". –

+1

Nó sẽ vẫn hoạt động bất kể, tôi vừa kiểm tra. –