產生預先簽章的 URL 來上傳物件 - Amazon Simple Storage Service

產生預先簽章的 URL 來上傳物件

如果預先簽章的 URL 建立者具有 URL 中所識別之物件的存取許可,則預先簽章的 URL 即可讓您存取該物件。也就是說,如果您收到上傳物件的預先簽章 URL,則只有該預先簽章的 URL 建立者具有上傳該物件的必要許可時,您才能上傳物件。

所有物件與儲存貯體預設皆為私有。如果您希望使用者/客戶能夠將特定物件上傳至儲存貯體,但不想讓他們具備 AWS 安全憑證或許可,即可使用預先簽章的 URL。

當您建立預先簽章的 URL 時,必須提供您的安全憑證,然後指定儲存貯體名稱、物件金鑰、HTTP 方法 (上傳物件時為 PUT),以及過期日期與時間。預先簽章的 URL 只有在指定的期間內才有效。也就是說,您必須在到期日期和時間之前啟動操作。

如果動作包含多個步驟 (例如分段上傳),則所有步驟都必須在到期之前啟動。否則,當 Amazon S3 嘗試以過期 URL 啟動步驟時,您將會收到錯誤訊息。

您可以多次使用此預先簽章 URL,直到到期日期和時間為止。

存取預先簽章的 URL

由於預先簽章 URL 會將 Amazon S3 儲存貯體的存取權授予擁有 URL 的任何人,因此我們建議您妥善保護這些 URL。如需保護預先簽章的 URL 的詳細資訊,請參閱限制預先簽章的 URL 功能

任何具備有效安全憑證的使用者,均可建立預先簽章的 URL。不過,為了讓您能順利上傳物件,只有具預先簽章 URL 之操作執行許可的人員,才能建立預先簽章的 URL。如需詳細資訊,請參閱「誰可以建立預先簽章的 URL」。

為上傳物件產生預先簽章的 URL

您可以使用適用於 .NET、Java、Ruby、JavaScript、PHP 和 Python 的 AWS SDK,以程式設計方式產生預先簽章的 URL。

您可以使用 AWS SDK 來產生預先簽章的 URL,您或收到您提供之 URL 的任何人都可以用來將物件上傳到 Amazon S3。當您使用 URL 上傳物件時,Amazon S3 會於指定儲存貯體建立物件。如果儲存貯體中已具備您在預先簽章 URL 中指定之相同金鑰的物件,則 Amazon S3 會使用上傳的物件來取代現有的物件。

如果您使用的是 Microsoft Visual Studio,也可以使用 AWS Toolkit for Visual Studio 中的 AWS Explorer 產生預先簽章的物件 URL,而無須撰寫任何程式碼。任何收到有效預先簽章 URL 的使用者,均可透過編寫程式的方式上傳物件。如需詳細資訊,請參閱《AWS Toolkit for Visual Studio 使用者指南》中的從 AWS Explorer 使用 Amazon S3

如需如何安裝 AWS Explorer 的說明,請參閱使用 AWS SDK 和 Explorer 來透過 Amazon S3 進行開發

下列範例示範如何使用預先簽章 URL 上傳物件。

下列程式碼範例示範如何建立適用於 S3 預先簽署的 URL 並上傳物件。

Go
SDK for Go V2
提示

若要瞭解如何設定和執行此範例,請參閱 GitHub

// 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) presignResult, err := presignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{ Bucket: aws.String(name), Key: aws.String("path/myfile.jpg"), }) if err != nil { panic("Couldn't get presigned URL for GetObject") } fmt.Printf("Presigned URL For object: %s\n", presignResult.URL)
Java
SDK for Java 2.x
提示

若要瞭解如何設定和執行此範例,請參閱 GitHub

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 for JavaScript V3
提示

若要瞭解如何設定和執行此範例,請參閱 GitHub

建立用戶端。

// 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 };

建立預先簽署的 URL 將物件上傳至儲存貯體。

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

建立預先簽署的 URL 從儲存貯體下載物件。

// 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();
  • 如需詳細資訊,請參閱《AWS SDK for JavaScript 開發人員指南》。

Python
SDK for Python (Boto3)
提示

若要瞭解如何設定和執行此範例,請參閱 GitHub

產生可以於限定時間內執行 S3 動作的預先簽署的 URL。使用 Requests package 搭配 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()

產生預先簽署的 POST 請求以上傳檔案。

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
適用於 Ruby 的 SDK
提示

若要瞭解如何設定和執行此範例,請參閱 GitHub

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__