2011-11-15 17 views
6

Estoy intentando crear una URL S3 firmada usando Javascript & NodeJS. He utilizado la especificación this .Creación de una URL S3 firmada 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 

Esto crea una URL similar a esta:

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

Sin embargo, recibo el siguiente error al acceder a él:

SignatureDoesNotMatch 

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

¿Qué estoy haciendo mal al crear la firma?

EDITAR - INTENTO CON KNOX

ahora que estoy tratando de utilizar Knox para producir una URL firmada. Necesito agregar encabezados con la solicitud para forzar la descarga. He editado el siguiente:

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

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

El mensaje que está siendo enviado a auth.hmacSha1 para crear el SIG es:

'GET\n\n\n1321374212\nresponse-content-disposition:attachment\n/meshmesh-dev/test/Readme.md' 

He intentado acceder a mi nueva URL con el response-content-disposition=attachment agregado como GET var. Sin embargo, sigo recibiendo el mismo error indicado anteriormente.

+0

Teniendo el mismo problema que usted, ¿se ha resuelto alguna vez? –

Respuesta

8

Yo trataría de usar Knox junto con Node.Js. Su conocidos por ser una gran combinación y también en sí utiliza la biblioteca Node.JS Crypto que es una especie de lo que estamos tratando de hacer - que le ahorra tiempo :)

Más información aquí: https://github.com/LearnBoost/knox

que, usted Sólo podría hacer algo como:

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

Editar: también podría mirar en Knox y simplemente comprobar lo que hace la función signedUrl e implementar yourself.Than que se podría añadir a la llamada auth.signQuery una opción adicional llamada 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

Gracias. Estaba usando Knox, pero necesitaba enviar encabezados con la solicitud ('response-content-disposition ': attachment'), así que traté de firmar mis propias URL. ¿Alguna idea de cómo se hace esto con Knox? – Kit

+1

Editado mi respuesta –

+1

gracias. Probando algunas cosas ahora ... – Kit

3

tal vez demasiadas nuevas líneas?

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

Si su ayuda aquí es una aplicación PHP basura que sin duda funciona:

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

Tener un vistazo a este nodo.js s3 código de carga, (no es mío, pero lo encontré en mi mac, así que si alguien puede atribuírselo a alguien, avísame y haré los puntales). Espero que esto podría ayudar (tercera va la vencida)

https://gist.github.com/1370593

+0

gracias. Trataré de descubrir qué función está haciendo la función anterior. Sin embargo, incluso sin el '\ n' adicional después de la fecha de caducidad, sig todavía falla. – Kit

+0

Lo siento es un poco obtuso y no está en el idioma correcto para usted, pero es lo primero que tenía que ofrecer, si tiene alguna pregunta hágamelo saber. –

+0

Una última oportunidad ... ¿Debería estar el depósito en el recurso .e.g /mybucket/test.txt no solo en /text.txt? –

0

Mi aplicación utilizando AWS-SDK y 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(); 
     }); 
    }); 
} 
Cuestiones relacionadas