Open5

Supabase の Storage のオブジェクトの URL を JS で取得する2通りの方法

プログラミングをするパンダプログラミングをするパンダ

Supabase の Storage のオブジェクトの URL を取得する

Supabase の Storage のオブジェクトの URL を取得する方法は2通りある。

  1. Bucket が Public ではないとき、object を download してから URL を取得する
  2. Bucket が Public であるとき、getPublicUrl を使う
プログラミングをするパンダプログラミングをするパンダ

Bucket が Public ではないときの URL 取得方法

公式ドキュメント に書かれている Bucket のポリシーを適用する。

insert into storage.buckets (id, name) values ('avatars', 'avatars');

create policy "Public Access"
on storage.objects for select
using ( bucket_id = 'public' );

SQLを実行すると作成された Bucket は Public ではない。実際、avatars Bucket には Public ラベルが付与されていない。

Bucket の名前リスト

このとき、画像などのオブジェクトをこの Bucket にアップロードすると、発行される URL は signed url である。

例えば、filename.jpgavatarsBucket にアップロードしたとすると、以下のような URL が発行される。

https://randomstring.supabase.in/storage/v1/object/sign/avatars/filename.jpg?token=long-random-string-token

このオブジェクトの URL を JS で取得する方法は以下の通り。

const { data, error } = await supabase.storage.from('avatars').download('filename.jpg')

if (data === null) return

const url = URL.createObjectURL(data)

data の型は Blob | null

この方法は Supabase の Next.js のサンプル に記述されている。

プログラミングをするパンダプログラミングをするパンダ

Bucket が Public のときのオブジェクトの URL 取得方法

まずは Public な Bucket を作成する。GUI でも可能だが、ここでは SQL の方法を紹介する。

insert into storage.buckets (id, name, public) values ('avatars', 'avatars', true);

Bucket が Public か否かは storage.buckets テーブルのカラムを見ればわかる。このため、Bucket 作成時に Public フラグを true にしておく。

この SQL を実行すると、avatars Bucket は Public になる。

avatars Bucket に Public ラベルが付与されている

この Bucket にfilename.jpgをアップロードすると、以下のような URL が得られる。

https://randomstring.supabase.in/storage/v1/object/public/avatars/filename.jpg

これを JS で取得するコードは以下の通り。

const url = await supabase.storage.from('avatars').getPublicUrl('filename.jpg')
プログラミングをするパンダプログラミングをするパンダ

上記では Bucket にポリシーを付与していない。しかし、基本的には以下のようなポリシーを設定すると良いだろう。

create policy "Avatar images are publicly accessible."
  on storage.objects for select using ( bucket_id = 'avatars' );

create policy "Logged-in user can upload an avatar."
  on storage.objects for insert with check ( bucket_id = 'avatars' AND role() = 'authenticated' );

create policy "Users can update their own avatar."
  on storage.objects for update with check ( bucket_id = 'avatars' AND uid() = owner );

create policy "Users can delete their own avatar."
  on storage.objects for update with check ( bucket_id = 'avatars' AND uid() = owner );

これで、参照は誰でも可能、アップロードはログイン済みユーザー、更新、削除は所有者(アップロードした人)のみに制限できる。

ZUKU(お役に立てたら👍イイねオネガイシマース)ZUKU(お役に立てたら👍イイねオネガイシマース)

共有ありがとうございます。

相談なのですが、
1. Bucket が Public ではないとき、object を download してから URL を取得する
だとURLに比べると表示スピードはかなり遅くなりそうな感覚なのですがいかがでしょう?

今supabaseのstorageを使うか、直接awsのS3にするか選定しており、
特定のアクセス権を持つユーザーだけが保存した画像を閲覧できるようにしたいと考えています。
supabaseのstorageを使うとなると、downloadするしかなさそうですよね。。