Generación de una URL prefirmada para cargar un objeto - Amazon Simple Storage Service

Generación de una URL prefirmada para cargar un objeto

Una dirección URL prefirmada le permite acceder al objeto identificado en la misma, siempre que el creador de la URL prefirmada tenga permiso para obtener acceso al objeto. Es decir, si recibe una URL prefirmada para cargar un objeto, podrá cargar el objeto solamente si el creador de la URL prefirmada cuenta con los permisos necesarios para ello.

De forma predeterminada, todos los objetos y buckets son privados. Las direcciones URL prefirmadas resultan útiles si desea que su cliente o usuario pueda cargar un objeto específico en su bucket, pero no quiere que tenga permisos o credenciales de seguridad de AWS.

Al crear una dirección URL prefirmada, debe facilitar sus credenciales de seguridad y, a continuación, especificar un nombre para el bucket, una clave de objeto, un método HTTP (PUT para cargar objetos) y una fecha y hora de vencimiento. Las URL prefirmadas son solo válidas para la duración especificada. Es decir, debe comenzar la acción antes de la fecha y hora de vencimiento.

Si la acción consta de varios pasos, como una carga multiparte, todos los pasos deben comenzar antes del vencimiento. De lo contrario, recibirá un error cuando Amazon S3 intente comenzar un paso con una URL vencida.

Puede utilizar la URL prefirmada varias veces, hasta la fecha y hora de vencimiento.

Acceso a URL prefirmadas

Dado que las URL prefirmadas otorgan acceso a los buckets de Amazon S3 a quien tenga la URL, recomendamos que los proteja adecuadamente. Para obtener más información sobre la protección de las URL prefirmadas, consulte Limitación de las capacidades de URL prefirmadas.

Cualquiera que tenga credenciales de seguridad válidas puede crear una URL prefirmada. Sin embargo, para que pueda cargar un objeto correctamente, la URL prefirmada debe haber sido creada por alguien que tenga permisos para realizar la operación en la que se basa la URL prefirmada. Para obtener más información, consulte Quién puede crear una URL prefirmada.

Generación de una URL prefirmada para cargar objetos

Puede generar una URL prefirmada mediante programación con la ayuda de los AWS SDK para .NET, Java, Ruby, JavaScript, PHP y Python.

Puede utilizar el AWS SDK para generar una URL prefirmada que usted, o cualquier persona que reciba la URL, puede utilizar para cargar un objeto en Amazon S3. Cuando usa la URL para cargar un objeto, Amazon S3 crea el objeto en el bucket especificado. Si ya existe en el bucket un objeto con la misma clave que se ha especificado en la URL prefirmada, Amazon S3 reemplaza el objeto existente con el objeto cargado.

Si utiliza Microsoft Visual Studio, puede generar una URL de objeto prefirmada sin necesidad de escribir código alguno gracias al uso de AWS Explorer en AWS Toolkit for Visual Studio. Cualquiera que reciba una URL prefirmada válida puede cargar un objeto mediante programación. Para obtener más información, consulte Uso de Amazon S3 desde AWS Explorer en la Guía del usuario de AWS Toolkit for Visual Studio.

Para obtener instrucciones acerca de cómo instalar AWS Explorer, consulte Desarrollo con Amazon S3 mediante los SDK de AWS y los exploradores.

En los ejemplos siguientes se muestra cómo cargar objetos con URL prefirmadas.

En los siguientes ejemplos de código, se muestra cómo crear una URL prefirmada para S3 y cargar un objeto.

Go
SDK para Go V2
nota

Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS.

// Get a presigned URL for the object. // In order to get a presigned URL for an object, you must // create a Presignclient fmt.Println("Create Presign client") presignClient := s3.NewPresignClient(&client) presignParams := &s3.GetObjectInput{ Bucket: aws.String(name), Key: aws.String("path/myfile.jpg"), } // Apply an expiration via an option function presignDuration := func(po *s3.PresignOptions) { po.Expires = 5 * time.Minute } presignResult, err := presignClient.PresignGetObject(context.TODO(), presignParams, presignDuration) if err != nil { panic("Couldn't get presigned URL for GetObject") } fmt.Printf("Presigned URL For object: %s\n", presignResult.URL)
Java
SDK para Java 2.x
nota

Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS.

public static void signBucket(S3Presigner presigner, String bucketName, String keyName) { try { PutObjectRequest objectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(keyName) .contentType("text/plain") .build(); PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(10)) .putObjectRequest(objectRequest) .build(); PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest); String myURL = presignedRequest.url().toString(); System.out.println("Presigned URL to upload a file to: " +myURL); System.out.println("Which HTTP method needs to be used when uploading a file: " + presignedRequest.httpRequest().method()); // Upload content to the Amazon S3 bucket by using this URL. URL url = presignedRequest.url(); // Create the connection and use it to upload the new object by using the presigned URL. HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestProperty("Content-Type","text/plain"); connection.setRequestMethod("PUT"); OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream()); out.write("This text was uploaded as an object by using a presigned URL."); out.close(); connection.getResponseCode(); System.out.println("HTTP response code is " + connection.getResponseCode()); } catch (S3Exception | IOException e) { e.getStackTrace(); } }
JavaScript
SDK para JavaScript V3
nota

Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS.

Cree el cliente.

// Create service client module using ES6 syntax. import { S3Client } from "@aws-sdk/client-s3"; // Set the AWS Region. const REGION = "us-east-1"; // Create an Amazon S3 service client object. const s3Client = new S3Client({ region: REGION }); export { s3Client };

Cree una URL prefirmada para cargar un objeto en un bucket.

// Import the required AWS SDK clients and commands for Node.js import { CreateBucketCommand, DeleteObjectCommand, PutObjectCommand, DeleteBucketCommand } from "@aws-sdk/client-s3"; import { s3Client } from "./libs/s3Client.js"; // Helper function that creates an Amazon S3 service client module. import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import fetch from "node-fetch"; // Set parameters // Create a random name for the Amazon Simple Storage Service (Amazon S3) bucket and key export const bucketParams = { Bucket: `test-bucket-${Math.ceil(Math.random() * 10 ** 10)}`, Key: `test-object-${Math.ceil(Math.random() * 10 ** 10)}`, Body: "BODY" }; export const run = async () => { try { // Create an S3 bucket. console.log(`Creating bucket ${bucketParams.Bucket}`); await s3Client.send(new CreateBucketCommand({ Bucket: bucketParams.Bucket })); console.log(`Waiting for "${bucketParams.Bucket}" bucket creation...`); } catch (err) { console.log("Error creating bucket", err); } try { // Create a command to put the object in the S3 bucket. const command = new PutObjectCommand(bucketParams); // Create the presigned URL. const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600, }); console.log( `\nPutting "${bucketParams.Key}" using signedUrl with body "${bucketParams.Body}" in v3` ); console.log(signedUrl); const response = await fetch(signedUrl, {method: 'PUT', body: bucketParams.Body}); console.log( `\nResponse returned by signed URL: ${await response.text()}\n` ); } catch (err) { console.log("Error creating presigned URL", err); } try { // Delete the object. console.log(`\nDeleting object "${bucketParams.Key}"} from bucket`); await s3Client.send( new DeleteObjectCommand({ Bucket: bucketParams.Bucket, Key: bucketParams.Key }) ); } catch (err) { console.log("Error deleting object", err); } try { // Delete the S3 bucket. console.log(`\nDeleting bucket ${bucketParams.Bucket}`); await s3Client.send( new DeleteBucketCommand({ Bucket: bucketParams.Bucket }) ); } catch (err) { console.log("Error deleting bucket", err); } }; run();

Cree una URL prefirmada para descargar un objeto de un bucket.

// Import the required AWS SDK clients and commands for Node.js import { CreateBucketCommand, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, DeleteBucketCommand } from "@aws-sdk/client-s3"; import { s3Client } from "./libs/s3Client.js"; // Helper function that creates an Amazon S3 service client module. import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const fetch = require("node-fetch"); // Set parameters // Create a random names for the S3 bucket and key. export const bucketParams = { Bucket: `test-bucket-${Math.ceil(Math.random() * 10 ** 10)}`, Key: `test-object-${Math.ceil(Math.random() * 10 ** 10)}`, Body: "BODY" }; export const run = async () => { // Create an S3 bucket. try { console.log(`Creating bucket ${bucketParams.Bucket}`); const data = await s3Client.send( new CreateBucketCommand({ Bucket: bucketParams.Bucket }) ); return data; // For unit tests. console.log(`Waiting for "${bucketParams.Bucket}" bucket creation...\n`); } catch (err) { console.log("Error creating bucket", err); } // Put the object in the S3 bucket. try { console.log(`Putting object "${bucketParams.Key}" in bucket`); const data = await s3Client.send( new PutObjectCommand({ Bucket: bucketParams.Bucket, Key: bucketParams.Key, Body: bucketParams.Body, }) ); return data; // For unit tests. } catch (err) { console.log("Error putting object", err); } // Create a presigned URL. try { // Create the command. const command = new GetObjectCommand(bucketParams); // Create the presigned URL. const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600, }); console.log( `\nGetting "${bucketParams.Key}" using signedUrl with body "${bucketParams.Body}" in v3` ); console.log(signedUrl); const response = await fetch(signedUrl); console.log( `\nResponse returned by signed URL: ${await response.text()}\n` ); } catch (err) { console.log("Error creating presigned URL", err); } // Delete the object. try { console.log(`\nDeleting object "${bucketParams.Key}"} from bucket`); const data = await s3Client.send( new DeleteObjectCommand({ Bucket: bucketParams.Bucket, Key: bucketParams.Key }) ); return data; // For unit tests. } catch (err) { console.log("Error deleting object", err); } // Delete the S3 bucket. try { console.log(`\nDeleting bucket ${bucketParams.Bucket}`); const data = await s3Client.send( new DeleteBucketCommand({ Bucket: bucketParams.Bucket, Key: bucketParams.Key }) ); return data; // For unit tests. } catch (err) { console.log("Error deleting object", err); } }; run();
Python
SDK para Python (Boto3)
nota

Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS.

Genere una URL prefirmada que pueda realizar una acción de S3 durante un tiempo limitado. Utilice el paquete Requests para realizar una solicitud con la URL.

import argparse import logging import boto3 from botocore.exceptions import ClientError import requests logger = logging.getLogger(__name__) def generate_presigned_url(s3_client, client_method, method_parameters, expires_in): """ Generate a presigned Amazon S3 URL that can be used to perform an action. :param s3_client: A Boto3 Amazon S3 client. :param client_method: The name of the client method that the URL performs. :param method_parameters: The parameters of the specified client method. :param expires_in: The number of seconds the presigned URL is valid for. :return: The presigned URL. """ try: url = s3_client.generate_presigned_url( ClientMethod=client_method, Params=method_parameters, ExpiresIn=expires_in ) logger.info("Got presigned URL: %s", url) except ClientError: logger.exception( "Couldn't get a presigned URL for client method '%s'.", client_method) raise return url def usage_demo(): logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') print('-'*88) print("Welcome to the Amazon S3 presigned URL demo.") print('-'*88) parser = argparse.ArgumentParser() parser.add_argument('bucket', help="The name of the bucket.") parser.add_argument( 'key', help="For a GET operation, the key of the object in Amazon S3. For a " "PUT operation, the name of a file to upload.") parser.add_argument( 'action', choices=('get', 'put'), help="The action to perform.") args = parser.parse_args() s3_client = boto3.client('s3') client_action = 'get_object' if args.action == 'get' else 'put_object' url = generate_presigned_url( s3_client, client_action, {'Bucket': args.bucket, 'Key': args.key}, 1000) print("Using the Requests package to send a request to the URL.") response = None if args.action == 'get': response = requests.get(url) elif args.action == 'put': print("Putting data to the URL.") try: with open(args.key, 'r') as object_file: object_text = object_file.read() response = requests.put(url, data=object_text) except FileNotFoundError: print(f"Couldn't find {args.key}. For a PUT operation, the key must be the " f"name of a file that exists on your computer.") if response is not None: print("Got response:") print(f"Status: {response.status_code}") print(response.text) print('-'*88) if __name__ == '__main__': usage_demo()

Genere una solicitud POST prefirmada para cargar un archivo.

class BucketWrapper: """Encapsulates S3 bucket actions.""" def __init__(self, bucket): """ :param bucket: A Boto3 Bucket resource. This is a high-level resource in Boto3 that wraps bucket actions in a class-like structure. """ self.bucket = bucket self.name = bucket.name def generate_presigned_post(self, object_key, expires_in): """ Generate a presigned Amazon S3 POST request to upload a file. A presigned POST can be used for a limited time to let someone without an AWS account upload a file to a bucket. :param object_key: The object key to identify the uploaded object. :param expires_in: The number of seconds the presigned POST is valid. :return: A dictionary that contains the URL and form fields that contain required access data. """ try: response = self.bucket.meta.client.generate_presigned_post( Bucket=self.bucket.name, Key=object_key, ExpiresIn=expires_in) logger.info("Got presigned POST URL: %s", response['url']) except ClientError: logger.exception( "Couldn't get a presigned POST URL for bucket '%s' and object '%s'", self.bucket.name, object_key) raise return response
Ruby
SDK para Ruby
nota

Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS.

require "aws-sdk-s3" require "net/http" # Creates a presigned URL that can be used to upload content to an object. # # @param bucket [Aws::S3::Bucket] An existing Amazon S3 bucket. # @param object_key [String] The key to give the uploaded object. # @return [URI, nil] The parsed URI if successful; otherwise nil. def get_presigned_url(bucket, object_key) url = bucket.object(object_key).presigned_url(:put) puts "Created presigned URL: #{url}." URI(url) rescue Aws::Errors::ServiceError => e puts "Couldn't create presigned URL for #{bucket.name}:#{object_key}. Here's why: #{e.message}" end def run_demo bucket_name = "doc-example-bucket" object_key = "my-file.txt" object_content = "This is the content of my-file.txt." bucket = Aws::S3::Bucket.new(bucket_name) presigned_url = get_presigned_url(bucket, object_key) return unless presigned_url response = Net::HTTP.start(presigned_url.host) do |http| http.send_request("PUT", presigned_url.request_uri, object_content, "content_type" => "") end case response when Net::HTTPSuccess puts "Content uploaded!" else puts response.value end end run_demo if $PROGRAM_NAME == __FILE__