2차 공부/TIL

SnapRoad에서 SignedUrl을 사용한 이유

공대탈출 2024. 11. 18. 01:24

SnapRoad 서비스는 어떤 서비스인가?

SnapRoad는 private 그룹을 통해 개인, 그룹의 여행 기록과 사진, 텍스트를 그룹원들만 볼 수 있도록 안전하게 공유하는 서비스입니다. supabase의 private storage와 signed url은 snaproad의 특징인 프라이빗 그룹을 위한 개인정보 보호와 보안성을 구현하는데 핵심 역할을 한다.

 

왜 Signed Url을 사용했나?

Supabase의 storage는 기본적으로 public, private 버킷을 제공하며, private 버킷은 인증된 요청만 접근할 수 있다. 하지만 하기 이유로 signed url을 사용한다.

  1. 프라이빗 스토리지의 안전성 유지
    • 버킷의 파일을 노출시키지 않고, 지정된 유효시간 동안 특정 url으로만 접근을 허용한다.
    • 사용자 인증 후 접근 권한을 제한하여 파일을 제공하기 때문에 데이터를 안전하게 보호할 수 있다.
  2. 일회성 링크로 효율적인 보안 관리
    • 지정된 유효시간동안 url이 유효하고, 만료 시 사용이 불가하다.
    • 비인가 사용자가 url을 비정상적인 경로로 획득하더라도 만료 시간이 지나면 접근이 불가하다.
  3. API 호출 간소화
    • 클라이언트에서 복잡한 인증 절차 없이 링크를 통해 파일을 바로 불러올 수 있다.
    • 이를 통해 UX를 개선하고, 보안을 유지할 수 있다.

Supabase SignedUrl 사용법

먼저 1개의 파일에 대한 url을 받아와야할 때는 createSignedUrl을 사용한다.

supabase에서 제공받은 토큰값은 쿠키로 관리하여 요청시 자동으로 요청헤더에 들어간다. 그 값을 통해 자동으로 url에 넣어 요청url을 만들어 준다. 인자로 path와 파일명을 묶은 문자열, url의 유효기간으로 설정할 값을 넣어서 요청을 보내 사용한다. 

const { data, error } = await supabase
  .storage
  .from('avatars')
  .createSignedUrl('folder/avatar1.png', 60)
  
// response
// https://example.supabase.co/storage/v1/object/sign/avatars/folder/avatar1.png?token=<TOKEN>

 

두번째로 여러 signedurl생성을 한 요청으로 보내기 위한 createSignedUrls이다. Promise.all이나 allsetteled를 사용하여 여러 createSignedUrl 요청을 하나로 묶어 보내도 되지만, HTTP1에서는 한번의 요청이 6개로 제한되기 때문에 첫 로딩에 사용하게 되면 성능이슈가 생길 수 있다. 따라서 여러 signedUrl을 받아야한다면 createSignedUrls가 적절하다.

signedUrl을 사용했던 것과 비슷하게 여러 문자열을 배열로 묶어 유효기간과 함께 보내면 배열 형태로 url묶음을 응답으로 보내준다.

const { data, error } = await supabase
  .storage
  .from('avatars')
  .createSignedUrls(['folder/avatar1.png', 'folder/avatar2.png'], 60)

// response
// [
//  {
//    "error": null,
//    "path": "folder/avatar1.png",
//    "signedURL": "/object/sign/avatars/folder/avatar1.png?token=<TOKEN>",
//    "signedUrl": "https://example.supabase.co/storage/v1/object/sign/avatars/folder/avatar1.png?token=<TOKEN>"
//  },
//  {
//    "error": null,
//    "path": "folder/avatar2.png",
//    "signedURL": "/object/sign/avatars/folder/avatar2.png?token=<TOKEN>",
//    "signedUrl": "https://example.supabase.co/storage/v1/object/sign/avatars/folder/avatar2.png?token=<TOKEN>"
//  }
// ]


하지만 js에서 createSignedUrls는 큰 단점이 하나 있다.

단일 url생성인 createSignedUrl은 transform옵션을 사용하여 이미지 파일 형식(jpg, png, webp, avif, ...)으로 변경하거나, width, height, quality, resize를 사용하여 이미지의 크기를 변경할 수도 있다.

기본적인 createSignedUrl은 이미지 파일의 퀄리티를 80%로 낮춰 사용자에게 보내주어 어느정도 최적화가 된 상태이다.

 

현재 SnapRoad의 signedUrl 요청 흐름도 / 최적화 예정 내역

현재 SnapRoad에서 signedUrl을 생성하는 흐름도는 위와 같다.

테이블 데이터를 받아와 테이블에 저장된 이미지 파일명을 받아오고, 그 파일명을 배열로 묶어 createSignedUrls를 통해 이미지 요청 경로를 받아온다.

Baas로 Supabase를 사용하다보니 이런 백엔드 서비스로직을 프론트에서 구현해야하여 요청이 나눠진 상태인데, 이를 sql function을 만들어 아예 처음부터 이미지 파일명이 아닌 signedUrl으로 만들어 클라이언트서버에 보내주는 것으로 최적화를 진행할 예정이다.

또한 createSignedUrls는 이미지 확장자나 퀄리티 지정과 같은 최적화를 사용할 수 없어 해당 부분도 같이 최적화를 진행할 예정이다.

최적화 후 예상 요청 흐름도는 아래와 같다.

불필요한 요청흐름을 제거하면 큰 성능향상이 이뤄질 것으로 예상되며, 각 이미지의 최적화 로직또한 supabase에서 제공해주기 때문에 이미지 src요청에서도 성능향상과 최적화가 이뤄질 것이라고 생각한다.