본문 바로가기

스터디-ing/Programming

[Java] Spring으로 S3 Signed URL 발급 받기

이전 글에서 S3에 파일을 올릴 때 Signed URL로 방식을 바꿔 네트워크 트래픽을 줄이는 방법을 도식화해서 공유했다.

2024.05.24 - [AWS/S3] - [S3] Signed URL로 파일 업로드, 트래픽 줄이기
 

[S3] Signed URL로 파일 업로드, 트래픽 줄이기

Signed URL? (출처 AWS 공식 문서)미리 서명된 URL의 생성자가 해당 객체에 대한 액세스 권한을 보유할 경우, 미리 서명된 URL은 URL에서 식별된 객체에 대한 액세스를 부여합니다.즉, 객체를 업로드하

devlogkm.tistory.com

 

이번 글에서는 Java Spring으로 Signed URL을 발급하는 코드를 공유하려 한다.

 

Signed URL 발급 구현

첫번째, AWS SDK를 사용하기 위한 dependency 추가가 필요하다.

software.amazom.awssdk.s3 를 추가한다.

 

build.gradle

```

dependencies {
    // AWS SDK for S3
    implementation 'software.amazon.awssdk:s3'
}

```

 

pom.xml

<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
    </dependency>
</dependencies>

 

 

두번째, AWS 자격 증명 발급

IAM 자격 증명을 이용해 Access key idSecret access key발급이 필요하다.

IAM 권한정책

IAM > 액세스 관리 > 사용자 > 액세스 유형을 프로그래밍 방식 액세스로 사용자 생성 하고 권한 설정에서 AmazonS3FullAccess 권한을 부여하면 Access key idSecret access key 를 발급해준다.

 

위에서 발급받은 Access key idSecret access keyAPI 서버 환경 변수properties 이외에 프로그래밍 상에서 사용할 방식으로 저장한다.

 

세번째, URL 발급 코드 작성

[ S3Service.java ]

import org.springframework.stereotype.Service;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;

import java.net.URL;
import java.time.Duration;

@Service
public class S3Service {
    private final S3Client s3Client;
    private final S3Presigner s3Presigner;
    private final String bucketName;

    public S3Service(@Value("${aws.s3.bucketname}") String bucketName,
                     @Value("${aws.accessKeyId}") String accessKeyId,
                     @Value("${aws.secretAccessKey}") String secretAccessKey) {
    	// AWS Credential 생성
        AwsBasicCredentials awsCreds = AwsBasicCredentials.create(
                accessKeyId,
                secretAccessKey
        );

        // S3 Region 설정
        this.s3Client = S3Client.builder()
                .region(Region.AP_NORTHEAST_2) // 지역 설정
                .credentialsProvider(StaticCredentialsProvider.create(awsCreds))
                .build();

        // S3 presigner 설정
        this.s3Presigner = S3Presigner.builder()
                .region(Region.US_EAST_1) // Replace with your region
                .credentialsProvider(StaticCredentialsProvider.create(awsCreds))
                .build();
        // S3 버킷 명 설정
        this.bucketName = bucketName;
    }

    // Signed URL 발급 함수
    // objectKey: S3 내부 path(Ex. "project/kikilog/test.text"
    // expiration: 만료 시간(s)
    public URL generateSignedUrl(String objectKey, Duration expiration) {
        GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                .bucket(bucketName)
                .key(objectKey)
                .build();

        GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder()
                .signatureDuration(expiration) 
                .getObjectRequest(getObjectRequest)
                .build();

        return s3Presigner.presignGetObject(getObjectPresignRequest).url();
    }
}

 

[ S3Controller ]

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.net.URL;
import java.time.Duration;

@RestController
public class S3Controller {

    @Autowired
    private S3Service s3Service;

    // 엔드포인트를 S3 객체 키(S3 내부 경로)로 사용
    @GetMapping("/generate-presigned-url/{objectKey}")
    public String generatePresignedUrl(
            @PathVariable String objectKey,
            @RequestParam(defaultValue = "60") int expirationMinutes) {
        // Signed URL 만료 시간
        Duration expiration = Duration.ofMinutes(expirationMinutes);
        
        // Signed URL 발
        URL signedUrl = s3Service.generatePresignedUrl(objectKey, expiration);

        return signedUrl.toString();
    }
}

 

이렇게 Signed URL을 발급 받아서 사용할 수 있고, 추가로 업로드 뿐만 아니라 다운로드 받을 수 있는 URL과 삭제, 복사 등 AWSSDK로 S3에 관련된 여러 동작을 코드로 구현할 수 있으니 참고하길 바란다!