使用 Amazon S3 预签名 URL - 适用于 Java 的 AWS 开发工具包版本 2
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

使用 Amazon S3 预签名 URL

您可以使用 S3Presigner 对象签名 Amazon S3SdkRequest,以便在不需要调用者身份验证的情况下执行该对象。例如,假设 Alice 有权访问 S3 对象,并希望临时与 Bob 共享对该对象的访问权限。Alice 可以生成预签名的 GetObjectRequest 对象以确保与 Bob 共享,这样 Bob 就可以下载该对象而无需访问 Alice 的凭证。

生成预签名 URL 并上传对象

构建表示客户端对象的 S3Presigner 对象。接下来创建一个可以在以后执行的 PuregnedputjectSequest 对象,而不需要额外的签名或身份验证。创建此对象时,您可以指定存储桶名称和密钥名称。此外,您还可以通过调用 signatureDuration 方法(如以下代码示例所示),指定可以在不使用凭证的情况下访问存储桶的时间(以分钟为单位)。

您可以通过调用 PresignedPutObjectRequest 对象的 url 方法来获取 URL。

导入

import java.io.IOException; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.time.Duration; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest; import software.amazon.awssdk.services.s3.presigner.S3Presigner;

代码

以下 Java 代码示例将内容上传到预签名的 S3 存储桶。

public static void signBucket( S3Presigner presigner, String bucketName, String keyName) { try { PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(z -> z.signatureDuration(Duration.ofMinutes(10)) .putObjectRequest(por -> por.bucket(bucketName).key(keyName))); System.out.println("Pre-signed URL to upload a file to: " + presignedRequest.url()); System.out.println("Which HTTP method needs to be used when uploading a file: " + presignedRequest.httpRequest().method()); // Upload content to the bucket by using this URL URL url = presignedRequest.url(); // Create the connection and use it to upload the new object by using the pre-signed 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 uploaded as an object via presigned URL."); out.close(); connection.getResponseCode(); System.out.println("HTTP response code: " + connection.getResponseCode()); /* * It's recommended that you close the S3Presigner when it is done being used, because some credential * providers (e.g. if your AWS profile is configured to assume an STS role) require system resources * that need to be freed. If you are using one S3Presigner per application (as recommended), this * usually isn't needed */ presigner.close(); } catch (S3Exception e) { e.getStackTrace(); } catch (IOException e) { e.getStackTrace(); }

请参阅 GitHub 上的完整示例

获取预签名对象

构建表示客户端对象的 S3Presigner 对象。接下来,创建一个 GetObjectSequest 对象并指定存储桶名称和密钥名称。此外,创建一个可以在以后执行的 GetObjectPresignRequest 对象,而不需要额外的签名或身份验证。当您创建此对象时,您可以通过调用 signatureDuration 方法(如以下代码示例所示)指定可以在不使用凭证的情况下访问存储桶的时间(以分钟为单位)。

调用属于 S3Presigner 对象的 presignGetObject 方法来创建一个 PresignedPutObjectRequest 对象。您可以调用此对象的 url 方法来获取要使用的 URL。获得 URL 后,您可以使用标准 HTTP Java 逻辑读取存储桶的内容,如以下 Java 代码示例所示。

导入

import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.time.Duration; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.utils.IoUtils;

代码

以下 Java 代码示例从预签名 S3 存储桶中读取内容。

public static void getPresignedUrl( S3Presigner presigner, String bucketName,String keyName ) { try { // Create a GetObjectRequest to be pre-signed GetObjectRequest getObjectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); // Create a GetObjectPresignRequest to specify the signature duration GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(10)) .getObjectRequest(getObjectRequest) .build(); // Generate the presigned request PresignedGetObjectRequest presignedGetObjectRequest = presigner.presignGetObject(getObjectPresignRequest); // Log the presigned URL System.out.println("Presigned URL: " + presignedGetObjectRequest.url()); // Create a JDK HttpURLConnection for communicating with S3 HttpURLConnection connection = (HttpURLConnection) presignedGetObjectRequest.url().openConnection(); // Specify any headers that the service needs (not needed when isBrowserExecutable is true) presignedGetObjectRequest.httpRequest().headers().forEach((header, values) -> { values.forEach(value -> { connection.addRequestProperty(header, value); }); }); // Send any request payload that the service needs (not needed when isBrowserExecutable is true) if (presignedGetObjectRequest.signedPayload().isPresent()) { connection.setDoOutput(true); try (InputStream signedPayload = presignedGetObjectRequest.signedPayload().get().asInputStream(); OutputStream httpOutputStream = connection.getOutputStream()) { IoUtils.copy(signedPayload, httpOutputStream); } } // Download the result of executing the request try (InputStream content = connection.getInputStream()) { System.out.println("Service returned response: "); IoUtils.copy(content, System.out); } /* * It's recommended that you close the S3Presigner when it is done being used, because some credential * providers (e.g. if your AWS profile is configured to assume an STS role) require system resources * that need to be freed. If you are using one S3Presigner per application (as recommended), this * usually isn't needed */ presigner.close(); } catch (S3Exception e) { e.getStackTrace(); } catch (IOException e) { e.getStackTrace(); }

请参阅 GitHub 上的完整示例