Comment générer une url temporaire pour télécharger le fichier sur Amazon S3 avec Boto library?

Je savais comment télécharger le fichier de cette façon-clé.generate_url(3600).

Mais quand j'ai essayé de télécharger: key.generate_url(3600, method= 'PUT'), l'url n'a pas fonctionné. On m'a dit: "La signature de la demande que nous avons calculée ne correspond pas à la signature que vous avez fournie. Vérifiez votre clé et votre méthode de signature."

Je ne trouve pas d'exemple de code dans la page d'accueil de boto pour savoir comment utiliser la fonction generate_url (method= 'PUT'). Quelqu'un ici sait comment l'utiliser pour le téléchargement? comment définir les paramètres de le chemin de télécharger le fichier?

22
demandé sur michael.luk 2012-04-06 17:28:31

4 réponses

J'ai trouvé un peu de temps pour expérimenter avec cela et voici ce que j'ai trouvé.

>>> import boto
>>> c =boto.connect_s3()
>>> fp = open('myfiletoupload.txt')
>>> content_length = len(fp.read())
>>> c.generate_url(300, 'PUT', 'test-1332789015', 'foobar', headers={'Content-Length': str(content_length)}, force_http=True)
'http://test-1332789015.s3.amazonaws.com/foobar?Signature=oUARG45mR95utXsiQYRJNiCI4x4%3D&Expires=1333731456&AWSAccessKeyId=AKIAJOTCCJRP4C3NSMYA&Content-Length=16'

J'ai ensuite pu utiliser curl pour mettre le fichier sur cette url comme ceci:

$ curl --request PUT --upload-file myfiletoupload.txt "http://test-1332789015.s3.amazonaws.com/foobar?Signature=oUARG45mR95utXsiQYRJNiCI4x4%3D&Expires=1333731456&AWSAccessKeyId=AKIAJOTCCJRP4C3NSMYA&Content-Length=16"

Cela a entraîné le téléchargement du fichier dans le compartiment. Ainsi, il apparaît que c'est possible. Vous voudrez peut-être voir si vous pouvez calculer la valeur content-md5 et l'inclure dans les en-têtes, mais vous devez également comprendre comment obtenir curl pour envoyer cet en-tête. Aussi, vous devriez être en mesure de faire ce travail sur HTTPS plutôt que HTTP mais je n'ai pas essayé cela.

42
répondu garnaat 2012-04-06 17:00:34

Voici à quoi cela ressemble dans boto3 (testé avec la version 1.2.3).

Tout d'abord, créez une url présignée avec la méthode s3.generate_presigned_url:

>>> import boto3
>>> s3 = boto3.client('s3')
>>> s3.generate_presigned_url('put_object', Params={'Bucket':'YourBucket', 'Key':'YourKey'}, ExpiresIn=3600, HttpMethod='PUT')
u'https://s3-ap-northeast-1.amazonaws.com/YourBucket/YourKey?AWSAccessKeyId=AKIAXXXXXXXXXXXXXXXX&Expires=1451061671&Signature=%2FtyAyCd5vrp13p%2FqLdoPkox7yTM%3D'

Mettre à S3 avec une URL présignée

$ curl \
  --request PUT \
  --upload-file path/to/file \
  "https://s3-ap-northeast-1.amazonaws.com/YourBucket/YourKey?AWSAccessKeyId=AKIAXXXXXXXXXXXXXXXX&Expires=1451061671&Signature=%2FtyAyCd5vrp13p%2FqLdoPkox7yTM%3D"
22
répondu quiver 2015-12-25 15:47:06

Toutes les autres réponses supposent que le fichier sera téléchargé avec curl, ce qui n'est vraiment pas pratique dans la plupart des scripts python. Dans ce qui suit, une url pré-signée est générée avec boto3 et le fichier est téléchargé avec la bibliothèque requests:

session = boto3.Session(aws_access_key_id="XXX", aws_secret_access_key="XXX")
s3client = session.client('s3')
url = s3client.generate_presigned_url('put_object', Params={'Bucket': 'mybucket', 'Key': 'mykey'})

requests.put(url, data=open("/path/to/file").read())
9
répondu Régis B. 2016-07-26 14:04:21

Ceci est une suite à la réponse de garnaat du 6 avril ' 12.

Je génère un côté serveur d'URL signé, où j'ai des informations d'identification, et je le passe à un client de sorte qu'un client puisse directement télécharger du contenu. Je fais assez confiance au client pour lui permettre de télécharger des fichiers de taille arbitraire, mais pas assez pour lui donner des jetons de sécurité. Je voulais éviter que le client indique au serveur la taille de son contenu dans le cadre de la requête. D'où mon suivi de la réponse.

J'ai pu obtenir l'url signée pour la méthode PUT fonctionne sans spécifier la longueur du contenu dans les en-têtes ou spécifier force_http=True.

En Utilisant Boto 2.31.1: comme dans la réponse de garnaat:

>>> import boto
>>> c =boto.connect_s3()

Alors à la place j'ai utilisé:

>>> temp_url = c.generate_url(seconds_available, 'PUT', bucket_name, s3_key)

Cela a produit une url sous la forme suivante:

https://s3_location/bucket_name/s3_key?Signature=Ew407JMktSIcFln%2FZe00VroCmTU%3D&Expires=1405647669&AWSAccessKeyId=kM__pEQo2AEVd_Juz4Qq

J'ai ensuite pu utiliser curl pour poster un fichier:

>>> os.system('curl --request PUT --upload-file true_measure/test_files/test_file_w_content.txt "'+temp_url+'"')

J'ai eu beaucoup de mal à comprendre cela parce que j'utilise habituellement requêtes python pour écrire des tests et déboguer; cependant, je obtenez un échec d'authentification lorsque j'essaie de l'utiliser pour placer un fichier dans l'une de ces URL signées générées par boto à l'aide de requêtes. Je n'ai pas complètement débogué cela, mais je soupçonne que c'est parce que requests ajoute quelques en-têtes supplémentaires par rapport à ce que curl produit.

J'espère que cette réponse de suivi épargnera à quelqu'un d'autre la douleur de débogage que j'ai traversée.

8
répondu user3525596 2014-07-18 17:23:47