2011-11-15 10 views
6

Sto tentando di creare un URL S3 firmato utilizzando Javascript & NodeJS. Ho usato la specifica this .Creazione di un URL S3 con segno con Javascript

var crypto  = require('crypto'), 
    date  = 1331290899, 
    resource = '/myfile.txt', 
    awskey  = "XXXX", 
    awssecret = "XXXX"; 

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

var sig = encodeURIComponent(crypto.createHmac('sha1', awssecret).update(stringToSign).digest('base64')); 

var url = "https://s3-eu-west-1.amazonaws.com/mybucket" + 
     resource + "?AWSAccessKeyId=" + awskey + "&Expires="+ date + 
     "&Signature="+ sig 

Questo crea un URL simile a questo:

https://s3-eu-west-1.amazonaws.com/mybucket/test.txt?AWSAccessKeyId=XXXXXX&Expires=1331290899&Signature=EciGxdQ1uOqgFDCRon4vPqTiCLc%3D 

Tuttavia, ricevo il seguente errore quando si accede a esso:

SignatureDoesNotMatch 

The request signature we calculated does not match the signature you provided. 
Check your key and signing method. 

Che cosa sto facendo di sbagliato durante la creazione della firma?

EDIT - TENTATIVO DI KNOX

ora sto tentando di utilizzare Knox per la produzione di un URL firmato. Devo aggiungere delle intestazioni con la richiesta per forzare il download. Ho modificato il seguente:

Aggiunto amazonHeaders: 'response-content-disposition:attachment', a client.signedUrl- http://jsfiddle.net/BpGNM/1/

Aggiunto options.amazonHeaders + '\n' + a auth.queryStringToSign - http://jsfiddle.net/6b8Tm/

Il messaggio che ora viene inviato a auth.hmacSha1 per creare il sig è:

Ho quindi provato ad accedere al mio nuovo URL con lo response-content-disposition=attachment aggiunto come GET var. Tuttavia, sto ancora ricevendo lo stesso errore sopra indicato.

+0

Avere lo stesso problema come te, è stato mai risolto? –

risposta

8

Vorrei provare a utilizzare Knox insieme a Node.Js. Il suo noto per essere una grande combinazione e anche se stesso utilizza la libreria Node.JS Crypto che è una specie di ciò che si sta cercando di fare - risparmiando tempo :)

Maggiori informazioni qui: https://github.com/LearnBoost/knox

Than, è poteva proprio fare qualcosa di simile:

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: si potrebbe anche prendere in considerazione Knox e basta controllare quale sia la funzione signedUrl fa e attuare tale yourself.Than si potrebbe aggiungere alla chiamata auth.signQuery un'opzione in più chiamato 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

Grazie. Stavo usando Knox, ma avevo bisogno di inviare intestazioni con la richiesta ('response-content-disposition ': attachment') - così ho provato a firmare i miei URL. Qualche idea su come sia fatto con Knox? – Kit

+1

Modificato la mia risposta per voi –

+1

grazie. Cercando alcune cose ora ... – Kit

3

forse uno troppi newline?

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

Se il suo aiuto: ecco un implementazione di PHP rifiuti che funziona sicuramente:

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

Date un'occhiata a questo nodo.js s3 upload code, (non è il mio ma lo trova in giro sul mio mac - quindi se qualcuno può attribuirlo a qualcuno fammelo sapere e io farò i puntelli). Speriamo che questo potrebbe aiutare (3 ° volta fortunato)

https://gist.github.com/1370593

+0

grazie. Cercherò di capire cosa sta facendo la funzione sopra riportata. Tuttavia, anche senza l'extra '\ n' dopo la data di scadenza, il sig non ha ancora successo. – Kit

+0

Scusa è un po 'ottuso e non è nella lingua giusta per te, ma è la prima cosa che dovevo dare - se hai qualche domanda fammelo sapere. –

+0

Un ultimo colpo ... Il bucket deve essere nella risorsa .e.g /mybucket/test.txt non solo /text.txt? –

0

mio implementazione utilizzando AWS-SDK e 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(); 
     }); 
    }); 
} 
Problemi correlati