기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
Amazon S3 미리 서명된 URLs 작업
미리 서명된 URLs 사용자가 AWS 자격 증명이나 권한을 가질 필요 없이 프라이빗 S3 객체에 대한 임시 액세스를 제공합니다.
예를 들어 Alice가 S3 객체에 대한 액세스 권한을 가지고 있고 해당 객체에 대한 액세스 권한을 Bob과 일시적으로 공유하려고 할 경우, Alice는 미리 서명된 GET 요청을 생성하여 Bob과 공유할 수 있으므로 Bob은 Alice의 보안 인증에 액세스하지 않고도 객체를 다운로드할 수 있습니다. HTTP GET 요청과 HTTP PUT 요청에 대해 미리 서명된 URL을 생성할 수 있습니다.
객체에 대해 미리 서명된 URL을 생성한 다음 다운로드(GET 요청)합니다.
다음 예시는 두 부분으로 구성되어 있습니다.
-
1부: Alice가 객체의 미리 서명된 URL을 생성합니다.
-
2부: Bob은 미리 서명된 URL을 사용하여 객체를 다운로드합니다.
1부: URL 생성
Alice는 이미 S3 버킷에 객체를 보유하고 있으며 다음 코드를 사용하여 Bob이 후속 GET 요청에서 사용할 수 있는 URL 문자열을 생성합니다.
import com.example.s3.util.PresignUrlUtils; import org.slf4j.Logger; import software.amazon.awssdk.http.HttpExecuteRequest; import software.amazon.awssdk.http.HttpExecuteResponse; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.apache.ApacheHttpClient; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; import software.amazon.awssdk.utils.IoUtils; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.file.Paths; import java.time.Duration; import java.util.UUID;
/* Create a pre-signed URL to download an object in a subsequent GET request. */ public String createPresignedGetUrl(String bucketName, String keyName) { try (S3Presigner presigner = S3Presigner.create()) { GetObjectRequest objectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(10)) // The URL will expire in 10 minutes. .getObjectRequest(objectRequest) .build(); PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(presignRequest); logger.info("Presigned URL: [{}]", presignedRequest.url().toString()); logger.info("HTTP method: [{}]", presignedRequest.httpRequest().method()); return presignedRequest.url().toExternalForm(); } }
2부: 객체 다운로드
Bob은 다음 코드 옵션 중 하나를 사용하여 객체를 다운로드합니다. 또는 브라우저를 사용하여 GET 요청을 수행할 수도 있습니다.
/* Use the JDK HttpURLConnection (since v1.1) class to do the download. */ public byte[] useHttpUrlConnectionToGet(String presignedUrlString) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array. try { URL presignedUrl = new URL(presignedUrlString); HttpURLConnection connection = (HttpURLConnection) presignedUrl.openConnection(); connection.setRequestMethod("GET"); // Download the result of executing the request. try (InputStream content = connection.getInputStream()) { IoUtils.copy(content, byteArrayOutputStream); } logger.info("HTTP response code is " + connection.getResponseCode()); } catch (S3Exception | IOException e) { logger.error(e.getMessage(), e); } return byteArrayOutputStream.toByteArray(); }
/* Use the JDK HttpClient (since v11) class to do the download. */ public byte[] useHttpClientToGet(String presignedUrlString) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array. HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(); HttpClient httpClient = HttpClient.newHttpClient(); try { URL presignedUrl = new URL(presignedUrlString); HttpResponse<InputStream> response = httpClient.send(requestBuilder .uri(presignedUrl.toURI()) .GET() .build(), HttpResponse.BodyHandlers.ofInputStream()); IoUtils.copy(response.body(), byteArrayOutputStream); logger.info("HTTP response code is " + response.statusCode()); } catch (URISyntaxException | InterruptedException | IOException e) { logger.error(e.getMessage(), e); } return byteArrayOutputStream.toByteArray(); }
/* Use the AWS SDK for Java SdkHttpClient class to do the download. */ public byte[] useSdkHttpClientToGet(String presignedUrlString) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array. try { URL presignedUrl = new URL(presignedUrlString); SdkHttpRequest request = SdkHttpRequest.builder() .method(SdkHttpMethod.GET) .uri(presignedUrl.toURI()) .build(); HttpExecuteRequest executeRequest = HttpExecuteRequest.builder() .request(request) .build(); try (SdkHttpClient sdkHttpClient = ApacheHttpClient.create()) { HttpExecuteResponse response = sdkHttpClient.prepareRequest(executeRequest).call(); response.responseBody().ifPresentOrElse( abortableInputStream -> { try { IoUtils.copy(abortableInputStream, byteArrayOutputStream); } catch (IOException e) { throw new RuntimeException(e); } }, () -> logger.error("No response body.")); logger.info("HTTP Response code is {}", response.httpResponse().statusCode()); } } catch (URISyntaxException | IOException e) { logger.error(e.getMessage(), e); } return byteArrayOutputStream.toByteArray(); }
는 SDK 비동기 파이프라인을 통해 미리 서명된 URL을 사용하여 객체를 다운로드S3AsyncClient하는에서 미리 서명된 URL 확장을 AWS SDK for Java 2.x 제공합니다. 를 사용하여 확장에 액세스합니다S3AsyncClient.presignedUrlExtension(). 이 기능은 SDK 버전 2.48.0 이상에서 사용할 수 있습니다.
CRT 클라이언트 제한
AWS CRT 기반 S3 클라이언트(S3AsyncClient.crtBuilder())는 현재 미리 서명된 URL 확장을 지원하지 않습니다. 대신 S3AsyncClient.builder()을 사용하세요.
체크섬 모드 요구 사항
데이터 무결성을 검증하려면 미리 서명된 URL을 생성할 GetObjectRequest 때 checksumMode(ChecksumMode.ENABLED)에를 설정합니다. 사전 서명 시 체크섬 모드를 지정합니다. 나중에 다운로드를 실행할 때는 추가할 수 없습니다. S3AsyncClient 미리 서명된 URL 확장을 사용하면 SDK가 필요한 x-amz-checksum-mode 헤더를 자동으로 전송합니다.
import java.nio.file.Paths; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.presignedurl.model.PresignedUrlDownloadRequest;
파일 또는 바이트로 다운로드
대용량 파일을 위한 멀티파트 다운로드
대용량 객체를 병렬로 다운로드하려면 클라이언트multipartEnabled(true)에서를 설정합니다.
Amazon S3 Transfer Manager 사용
Amazon S3 Transfer Manager를 사용하면를 통한 진행 상황 추적과 함께 미리 서명된 URLs 사용하여 객체를 다운로드할 수 있습니다TransferListener.
프로젝트에 아s3-transfer-manager티팩트를 추가합니다.
<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.48.01</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3-transfer-manager</artifactId> </dependency> </dependencies>
1 Maven Central Repository에서 최신 BOM 버전을 찾습니다
import java.nio.file.Paths; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.presignedurl.model.PresignedUrlDownloadRequest; import software.amazon.awssdk.transfer.s3.S3TransferManager; import software.amazon.awssdk.transfer.s3.model.CompletedFileDownload; import software.amazon.awssdk.transfer.s3.model.Download; import software.amazon.awssdk.transfer.s3.model.PresignedDownloadFileRequest; import software.amazon.awssdk.transfer.s3.model.PresignedDownloadRequest; import software.amazon.awssdk.transfer.s3.model.PresignedFileDownload; import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener;
일시 중지 및 재개가 지원되지 않음
일반와 달리 FileDownloadPresignedFileDownload는 미리 서명된 URLs 일시 중지된 전송 중에 만료될 수 있으므로 일시 중지 및 재개를 지원하지 않습니다.
구성 옵션 및 추가 예제를 포함하여 Amazon S3 Transfer Manager에 대한 자세한 내용은 섹션을 참조하세요Amazon S3 Transfer Manager로 파일 및 디렉터리 전송.
업로드를 위해 미리 서명된 URL을 생성한 다음 파일을 업로드(PUT 요청)합니다.
다음 예시는 두 부분으로 구성되어 있습니다.
-
1부: Alice는 객체를 업로드하기 위해 미리 서명된 URL을 생성합니다.
-
2부: Bob이 미리 서명된 URL을 사용하여 파일을 업로드합니다.
1부: URL 생성
Alice는 이미 S3 버킷을 보유하고 있으며 다음 코드를 사용하여 Bob이 후속 PUT 요청에서 사용할 수 있는 URL 문자열을 생성합니다.
import com.example.s3.util.PresignUrlUtils; import org.slf4j.Logger; import software.amazon.awssdk.core.internal.sync.FileContentStreamProvider; import software.amazon.awssdk.http.HttpExecuteRequest; import software.amazon.awssdk.http.HttpExecuteResponse; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.apache.ApacheHttpClient; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest; import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; import java.util.Map; import java.util.UUID;
/* Create a presigned URL to use in a subsequent PUT request */ public String createPresignedUrl(String bucketName, String keyName, Map<String, String> metadata) { try (S3Presigner presigner = S3Presigner.create()) { PutObjectRequest objectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(keyName) .metadata(metadata) .build(); PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(10)) // The URL expires in 10 minutes. .putObjectRequest(objectRequest) .build(); PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest); String myURL = presignedRequest.url().toString(); logger.info("Presigned URL to upload a file to: [{}]", myURL); logger.info("HTTP method: [{}]", presignedRequest.httpRequest().method()); return presignedRequest.url().toExternalForm(); } }
2부: 파일 객체 업로드
Bob은 다음 세 가지 코드 옵션 중 하나를 사용하여 파일을 업로드합니다.
/* Use the JDK HttpURLConnection (since v1.1) class to do the upload. */ public void useHttpUrlConnectionToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) { logger.info("Begin [{}] upload", fileToPut.toString()); try { URL presignedUrl = new URL(presignedUrlString); HttpURLConnection connection = (HttpURLConnection) presignedUrl.openConnection(); connection.setDoOutput(true); metadata.forEach((k, v) -> connection.setRequestProperty("x-amz-meta-" + k, v)); connection.setRequestMethod("PUT"); OutputStream out = connection.getOutputStream(); try (RandomAccessFile file = new RandomAccessFile(fileToPut, "r"); FileChannel inChannel = file.getChannel()) { ByteBuffer buffer = ByteBuffer.allocate(8192); //Buffer size is 8k while (inChannel.read(buffer) > 0) { buffer.flip(); for (int i = 0; i < buffer.limit(); i++) { out.write(buffer.get()); } buffer.clear(); } } catch (IOException e) { logger.error(e.getMessage(), e); } out.close(); connection.getResponseCode(); logger.info("HTTP response code is " + connection.getResponseCode()); } catch (S3Exception | IOException e) { logger.error(e.getMessage(), e); } }
/* Use the JDK HttpClient (since v11) class to do the upload. */ public void useHttpClientToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) { logger.info("Begin [{}] upload", fileToPut.toString()); HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(); metadata.forEach((k, v) -> requestBuilder.header("x-amz-meta-" + k, v)); HttpClient httpClient = HttpClient.newHttpClient(); try { final HttpResponse<Void> response = httpClient.send(requestBuilder .uri(new URL(presignedUrlString).toURI()) .PUT(HttpRequest.BodyPublishers.ofFile(Path.of(fileToPut.toURI()))) .build(), HttpResponse.BodyHandlers.discarding()); logger.info("HTTP response code is " + response.statusCode()); } catch (URISyntaxException | InterruptedException | IOException e) { logger.error(e.getMessage(), e); } }
/* Use the AWS SDK for Java V2 SdkHttpClient class to do the upload. */ public void useSdkHttpClientToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) { logger.info("Begin [{}] upload", fileToPut.toString()); try { URL presignedUrl = new URL(presignedUrlString); SdkHttpRequest.Builder requestBuilder = SdkHttpRequest.builder() .method(SdkHttpMethod.PUT) .uri(presignedUrl.toURI()); // Add headers metadata.forEach((k, v) -> requestBuilder.putHeader("x-amz-meta-" + k, v)); // Finish building the request. SdkHttpRequest request = requestBuilder.build(); HttpExecuteRequest executeRequest = HttpExecuteRequest.builder() .request(request) .contentStreamProvider(new FileContentStreamProvider(fileToPut.toPath())) .build(); try (SdkHttpClient sdkHttpClient = ApacheHttpClient.create()) { HttpExecuteResponse response = sdkHttpClient.prepareRequest(executeRequest).call(); logger.info("Response code: {}", response.httpResponse().statusCode()); } } catch (URISyntaxException | IOException e) { logger.error(e.getMessage(), e); } }