使用预签名 URL 上传对象 - Amazon Simple Storage Service
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

欢迎使用新的 Amazon S3 用户指南! Amazon S3 用户指南结合了以下三个已停用的指南中的信息和说明:Amazon S3 开发人员指南Amazon S3 控制台用户指南Amazon S3 入门指南

使用预签名 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

您可以使用适用于 Java、.NET、Ruby、PHP、Node.jsPython 的 AWS 开发工具包以编程方式生成预签名 URL。

如果您使用 Microsoft Visual Studio,还可以使用 AWS Explorer 来生成预签名对象 URL,无需编写任何代码。然后,收到有效预签名 URL 的任何人都可以采用编程的方式上传对象。有关详细信息,请参阅从 AWS Explorer 使用 Amazon S3。有关如何安装 AWS Explorer 的说明,请参阅使用 AWS 开发工具包和浏览器进行 Amazon S3 开发

您可以使用 AWS 开发工具包生成一个预签名 URL,您或者从您这里获得了该 URL 的任何人可使用该 URL 将对象上传到 Amazon S3。当使用该 URL 上传对象时,Amazon S3 将在指定存储桶中创建对象。如果存储桶中已存在具有预签名 URL 中指定的相同键的对象,则 Amazon S3 会将现有对象替换为上传的对象。

示例

以下示例说明如何使用预签名 URL 上传对象。

Java

要成功完成上传,必须执行以下操作:

  • 在创建 GeneratePresignedUrlRequestHttpURLConnection 对象时指定 HTTP PUT 谓词。

  • 在完成上传后以某种方式与 HttpURLConnection 对象交互。以下示例使用 HttpURLConnection 对象检查 HTTP 响应代码,从而达到此目的。

此示例将生成预签名 URL 并使用它将示例数据作为对象上传。有关创建和测试有效示例的说明,请参阅测试 Amazon S3 Java 代码示例

import com.amazonaws.AmazonServiceException; import com.amazonaws.HttpMethod; import com.amazonaws.SdkClientException; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; import com.amazonaws.services.s3.model.S3Object; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; public class GeneratePresignedUrlAndUploadObject { public static void main(String[] args) throws IOException { Regions clientRegion = Regions.DEFAULT_REGION; String bucketName = "*** Bucket name ***"; String objectKey = "*** Object key ***"; try { AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withCredentials(new ProfileCredentialsProvider()) .withRegion(clientRegion) .build(); // Set the pre-signed URL to expire after one hour. java.util.Date expiration = new java.util.Date(); long expTimeMillis = expiration.getTime(); expTimeMillis += 1000 * 60 * 60; expiration.setTime(expTimeMillis); // Generate the pre-signed URL. System.out.println("Generating pre-signed URL."); GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectKey) .withMethod(HttpMethod.PUT) .withExpiration(expiration); URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest); // Create the connection and use it to upload the new object using the pre-signed URL. HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("PUT"); OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream()); out.write("This text uploaded as an object via presigned URL."); out.close(); // Check the HTTP response code. To complete the upload and make the object available, // you must interact with the connection object in some way. connection.getResponseCode(); System.out.println("HTTP response code: " + connection.getResponseCode()); // Check to make sure that the object was uploaded successfully. S3Object object = s3Client.getObject(bucketName, objectKey); System.out.println("Object " + object.getKey() + " created in bucket " + object.getBucketName()); } catch (AmazonServiceException e) { // The call was transmitted successfully, but Amazon S3 couldn't process // it, so it returned an error response. e.printStackTrace(); } catch (SdkClientException e) { // Amazon S3 couldn't be contacted for a response, or the client // couldn't parse the response from Amazon S3. e.printStackTrace(); } } }
.NET

以下 C# 示例演示如何通过适用于 .NET 的 AWS 开发工具包使用预签名 URL 将对象上传到 S3 存储桶。

以下示例为特定对象生成预签名 URL 并使用此 URL 上传文件。有关示例与特定版本的适用于 .NET 的 AWS 开发工具包的兼容性信息以及有关如何创建和测试有效示例的说明,请参阅运行 Amazon S3 .NET 代码示例

using Amazon; using Amazon.S3; using Amazon.S3.Model; using System; using System.IO; using System.Net; namespace Amazon.DocSamples.S3 { class UploadObjectUsingPresignedURLTest { private const string bucketName = "*** provide bucket name ***"; private const string objectKey = "*** provide the name for the uploaded object ***"; private const string filePath = "*** provide the full path name of the file to upload ***"; // Specify how long the presigned URL lasts, in hours private const double timeoutDuration = 12; // Specify your bucket region (an example region is shown). private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2; private static IAmazonS3 s3Client; public static void Main() { s3Client = new AmazonS3Client(bucketRegion); var url = GeneratePreSignedURL(timeoutDuration); UploadObject(url); } private static void UploadObject(string url) { HttpWebRequest httpRequest = WebRequest.Create(url) as HttpWebRequest; httpRequest.Method = "PUT"; using (Stream dataStream = httpRequest.GetRequestStream()) { var buffer = new byte[8000]; using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { int bytesRead = 0; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0) { dataStream.Write(buffer, 0, bytesRead); } } } HttpWebResponse response = httpRequest.GetResponse() as HttpWebResponse; } private static string GeneratePreSignedURL(double duration) { var request = new GetPreSignedUrlRequest { BucketName = bucketName, Key = objectKey, Verb = HttpVerb.PUT, Expires = DateTime.UtcNow.AddHours(duration) }; string url = s3Client.GetPreSignedURL(request); return url; } } }
Ruby

以下任务引导您通过 Ruby 脚本使用适用于 Ruby 的 AWS 开发工具包(版本 3)的预签名 URL 来上传对象。

1

创建 Aws::S3::Resource 类的实例。

2

通过调用 #bucket[] 类实例的 #object[]Aws::S3::Resource 方法,提供存储桶名称和对象键。

通过创建 URI 类的实例生成预签名 URL,然后使用它分析 Aws::S3::Resource 类实例的 .presigned_url 方法。您必须将 :put 指定为 .presigned_url 的参数,如果需要上传对象,必须向 PUT 指定 Net::HTTP::Session#send_request

3

任何拥有预签名 URL 的人都可以上传对象。

上传将创建对象或将任何现有的对象替换为预签名 URL 中指定的相同键。

以下 Ruby 代码示例演示使用适用于 Ruby 的开发工具包(版本 3)实现上述任务。

require 'aws-sdk-s3' require 'net/http' # Uploads an object to a bucket in Amazon Simple Storage Service (Amazon S3) # by using a presigned URL. # # Prerequisites: # # - An S3 bucket. # - An object in the bucket to upload content to. # # @param s3_client [Aws::S3::Resource] An initialized S3 resource. # @param bucket_name [String] The name of the bucket. # @param object_key [String] The name of the object. # @param object_content [String] The content to upload to the object. # @param http_client [Net::HTTP] An initialized HTTP client. # This is especially useful for testing with mock HTTP clients. # If not specified, a default HTTP client is created. # @return [Boolean] true if the object was uploaded; otherwise, false. # @example # exit 1 unless object_uploaded_to_presigned_url?( # Aws::S3::Resource.new(region: 'us-east-1'), # 'doc-example-bucket', # 'my-file.txt', # 'This is the content of my-file.txt' # ) def object_uploaded_to_presigned_url?( s3_resource, bucket_name, object_key, object_content, http_client = nil ) object = s3_resource.bucket(bucket_name).object(object_key) url = URI.parse(object.presigned_url(:put)) if http_client.nil? Net::HTTP.start(url.host) do |http| http.send_request( 'PUT', url.request_uri, object_content, 'content-type' => '' ) end else http_client.start(url.host) do |http| http.send_request( 'PUT', url.request_uri, object_content, 'content-type' => '' ) end end content = object.get.body puts "The presigned URL for the object '#{object_key}' in the bucket " \ "'#{bucket_name}' is:\n\n" puts url puts "\nUsing this presigned URL to get the content that " \ "was just uploaded to this object, the object\'s content is:\n\n" puts content.read return true rescue StandardError => e puts "Error uploading to presigned URL: #{e.message}" return false end