AWS

S3 Presigned URL 생성 후 사용 방법

구로모논 2025. 11. 27. 22:44

S3 스토리지에서 업로드/다운로드 링크를 생성하는 방법입니다.

아래에서는 링크를 생성하는 예제만 작성할 것이고,

링크 생성 전, 사용자 인증, 권한 체크 등 필요한 보안 절차는 반드시 있어야 합니다.

 

1. Maven 의존성 추가

<dependencies>
    <!-- AWS S3 SDK -->
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
    </dependency>
</dependencies>

 

 

2. application.yml 설정

이 설정 내용 중 키 값 같은 것은 원하는 대로 하시면 됩니다.

cloud:
  aws:
    s3:
      bucket: ${BUCKET_NAME}
    credentials:
      access-key: ${AWS_ACCESS_KEY}
      secret-key: ${AWS_SECRET_KEY}
    region: ${REGION_NAME}

 

 

3. S3Client Bean

@Configuration
public class S3Config {

    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String secretKey;

    @Value("${cloud.aws.region}")
    private String region;

    @Bean
    public S3Client s3Client() {
        AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
        return S3Client.builder()
                .credentialsProvider(StaticCredentialsProvider.create(credentials))
                .region(Region.of(region))
                .build();
    }
    
    // Presigned URL 전용 S3Presigner
    @Bean
    public S3Presigner s3Presigner() {
        AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
        return S3Presigner.builder()
                .credentialsProvider(StaticCredentialsProvider.create(credentials))
                .region(Region.of(region))
                .build();
    }
}

 

 

4. Presigned URL 생성 서비스

@Service
@RequiredArgsConstructor
public class S3PresignedUrlService {

    private final S3Presigner s3Presigner;

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    // 업로드용 Presigned URL (PUT)
        
    public String generateUploadUrl(String fileName) {

        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                .bucket(bucket)
                .key(fileName)
                .build();

        PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
                .signatureDuration(Duration.ofMinutes(10)) // 유효시간
                .putObjectRequest(putObjectRequest)
                .build();

        PresignedPutObjectRequest presignedRequest =
                s3Presigner.presignPutObject(presignRequest);

        return presignedRequest.url().toString();
    }

    // 다운로드용 Presigned URL (GET)
    // 아래의 fileName 변수는 builder().key()에 들어가는데, 꼭 fileName만 들어가는 것은 아니고
    // 스토리지 디렉터리에 따라서 파일명을 포함한 경로가 들어갈 수도 있습니다.
    // 경로일 경우 -> dir/fileName 이런식으로
    public String generateDownloadUrl(String fileName, String downloadFileName) {

         GetObjectRequest getObjectRequest = GetObjectRequest.builder()
            .bucket(bucket)
            .key(fileName)
            .responseContentDisposition(
                    "attachment; filename=\"" + downloadFileName + "\""
            )
            .build();

        GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
                .signatureDuration(Duration.ofMinutes(5))
                .getObjectRequest(getObjectRequest)
                .build();

        PresignedGetObjectRequest presignedRequest =
                s3Presigner.presignGetObject(presignRequest);

        return presignedRequest.url().toString();
    }
}

 

 

5. Controller

@RestController
@RequiredArgsConstructor
@RequestMapping("/files")
public class FileDownloadController {

    private final S3PresignedUrlService presignedUrlService;

    /**
     * 파일 다운로드 요청 → 302로 S3 Presigned URL로 리다이렉트
     */
    @GetMapping("/{fileId}/download")
    public ResponseEntity<Void> redirectToS3(@PathVariable Long fileId) {

        // 1. 위에서 fileName은 경로를 포함할 수 있다고 설명드렸습니다.
        // 그래서 bucket내에서 디렉토리가 있는 경우에는 아래처럼 쓰시면 됩니다.
        String fileName = "uploads/2025/11/sample-" + fileId + ".pdf";
        String downloadFileName = "downloadFile.pdf";

        // 2. Content-Disposition 포함된 Presigned URL 생성
        String presignedUrl =
                presignedUrlService.generateDownloadUrl(s3Key, downloadFileName);

        // 3. 302 Redirect 응답 (Location 헤더에 presigned URL)
        return ResponseEntity.status(HttpStatus.FOUND)   // 302
                .location(URI.create(presignedUrl))
                .build();
    }
}

 

 

여기서 링크를 클라이언트로 보낸 후, 클라이언트에서 해당 링크로 요청하는 방법도 있습니다.

편하신대로 쓰시면 됩니다.

'AWS' 카테고리의 다른 글

S3 Presigned URL 간략 정리  (0) 2025.11.27
[AWS] RDS 외부 툴 연결  (0) 2023.01.09
[AWS] RDS 생성  (0) 2023.01.09