Creating a signed S3 URL with Javascript

前端 未结 3 964
情书的邮戳
情书的邮戳 2021-02-04 18:54

I am attempting to create a signed S3 URL using Javascript & NodeJS. I have used this specification.

var crypto     = require(\'crypto\'),
    date       =          


        
相关标签:
3条回答
  • 2021-02-04 19:08

    My implementation using AWS-SDK and Rx.

    import AWS from "aws-sdk"
    import Rx from 'rx'
    
    /*
    * Credentials could be loaded from env variables
    * http://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/loading-node-credentials-environment.html
    * */
    
    const s3 = new AWS.S3({apiVersion: '2006-03-01'});
    
    export function getS3SignedImage(objectKey) {
        return Rx.Observable.create(function (observer) {
            s3.getSignedUrl('getObject',{
                Bucket: process.env.AWS_BUCKET,
                Key: objectKey
            }, (err, data) => {
                if (err) {
                    return observer.onError(err);
                }
                observer.onNext(data);
                observer.onCompleted();
            });
        });
    }
    
    0 讨论(0)
  • 2021-02-04 19:15

    maybe one too many newlines?

    var stringToSign ='GET\n\n\n' + date + '\n\n' + resource;
    

    If its any help here is a rubbish PHP implementation which definitely works:

    class myS3Helper{
    public function getSignedImageLink($timeout = 1800)
        {
    
            $now = new Zend_Date(); //Gives us a time object that is set to NOW
            $now->setTimezone('UTC'); //Set to UTC a-la AWS requirements
            $now->addSecond($timeout);
            $expirationTime = $now->getTimestamp(); //returns unix timestamp representation of the time.
    
            $signature = urlencode(
                    base64_encode(
                            hash_hmac(
                                    'sha1', $this->_generateStringToSign($expirationTime),
                                    $my_aws_secretkey, 
                                    true
                                    )
                            )
                    );
    
            //FIXME make this less ugly when I know it works
            $url = 'https://';
            $url .= Zend_Service_Amazon_S3::S3_ENDPOINT; //e.g s3.amazonaws.com
            $url .= $this->_getImagePath(); //e.g /mybucket/myFirstCar.jpg
            $url .='?AWSAccessKeyId=' . $my_aws_key;
            $url .='&Signature=' . $signature; //signature as returned by below function
            $url .='&Expires=' . $expirationTime;
    
            return $url;
    
    
        }
    
        protected function _generateStringToSign($expires)
        {   
    
            $string = "GET\n"; //Methods
            $string .= "\n";
            $string .= "\n";
            $string .= "$expires\n"; //Expires
            $string .= $this->_getImagePath();
    
            return $string;
        }
    

    }

    EDIT--

    Have a look at this node.js s3 upload code, (it's not mine but found it lying around on my mac - so if anyone can attribute it to someone let me know and i'll do the props). Hopefully this might help (3rd time lucky)

    https://gist.github.com/1370593

    0 讨论(0)
  • 2021-02-04 19:29

    I would try using Knox along with Node.Js . Its known to be a great combination and also itself utilizes the Node.JS Crypto library which is kind of what you're trying to do - saving you time:)

    More info here : https://github.com/LearnBoost/knox

    Than, you could just do something like:

    var knox = require('knox');
    var s3Client = knox.createClient({
        key: 'XXX',
        secret: 'XXX',
        bucket: 'XXX'
    });
    
    var expires = new Date();
    expires.setMinutes(expires.getMinutes() + 30);
    var url =  s3Client.signedUrl(filename, expires);
    

    Edit: You could also look into Knox and just check what the signedUrl function does and implement that yourself.Than you could add to the auth.signQuery call an extra option called amazonHeaders:

    Client.prototype.signedUrl = function(filename, expiration){
      var epoch = Math.floor(expiration.getTime()/1000);
      var signature = auth.signQuery({
        amazonHeaders: 'response-content-disposition:attachment',
        secret: this.secret,
        date: epoch,
        resource: '/' + this.bucket + url.parse(filename).pathname
      });
    
      return this.url(filename) +
        '?Expires=' + epoch +
        '&AWSAccessKeyId=' + this.key +
        '&Signature=' + encodeURIComponent(signature);
    };
    

    Shai.

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