Amazon S3 POST api, and signing a policy with NodeJS

后端 未结 4 1297
轮回少年
轮回少年 2020-12-24 03:08

I\'m trying to get an built that allows users to upload a file directly to my Amazon S3 bucket, from a NodeJS powered website. It seems the only tutorials out there, other t

相关标签:
4条回答
  • 2020-12-24 03:21

    Ok, I finally figured it out. After playing the random guessing game for a VERY long time, I thought to myself

    "maybe i need to sign the base64 encoded policy" - me

    and BAM that was it.

    I also re-ordered the conditions to match how the form is posting, though I'm not sure this makes a difference.

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

    Hopefully this will help others that run in to the same problem.

    0 讨论(0)
  • 2020-12-24 03:26

    I continued to have issues, so I worked through them and posted my solution here:

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

    In short, if you go with scabbiaza's answer in building the signature, make sure to build the form like so:

    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 讨论(0)
  • 2020-12-24 03:31

    I modified a bit previous example, because it didn't work for me: amazon returned an error about broken signature.

    Here is how the signature should be created for Browser-Based Uploads Using POST (AWS Signature Version 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);
    

    Next generated base64Policy and s3Signature i used in the form for uploading. Example is here: http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html

    Very important is to check that you have the same fields and values in the html form and in your policy.

    0 讨论(0)
  • 2020-12-24 03:32

    AWS SDK now provides an easy way to create the POST policy with createPresignedPost().

    Docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#createPresignedPost-property

    0 讨论(0)
提交回复
热议问题