🏜️

Supabase Storage RLS

2023/08/23に公開

Overview

https://supabase.com/docs/guides/storage/access-control
公式より引用
Supabase StorageはPostgresデータベースと統合されています。
つまり、同じ行レベルのセキュリティポリシー
を使用することができます。Supabase Storageはストレージスキーマのobjectsとbucketsテーブルにメタデータを保存します。

ファイルへの読み取りアクセスを許可するには、RLS ポリシーでユーザーにオブジェクトテーブルの SELECT を許可し、新しいオブジェクトをアップロードするには、RLS ポリシーでユーザーにオブジェクトテーブルへの INSERT などのアクセスを許可する必要があります。各種 API 呼び出しと必要なデータベース権限との対応については、リファレンス ドキュメントを参照してください。


パブリックバケットとプライベートバケット#
ストレージバケットはデフォルトではプライベートです。プライベートバケットでは、ダウンロードメソッドでオブジェクトにアクセスできます。これは /object/auth/ API エンドポイントに相当します。
あるいは、/object/signUrl を呼び出す createSignedUrl メソッドを使って、有効期限付きの公開共有可能な URL を作成することもできます。
メソッドを使用して、有効期限付きの公開共有URLを作成することもできます。

公開バケットでは、トークンやAuthorisationヘッダなしで直接アセットにアクセスできます。getPublicUrl
ヘルパーメソッドは、アセットの完全な公開 URL を返します。これは、内部的に /object/public/ API エンドポイントを呼び出します。public Bucket 内のオブジェクトにアクセスする際には認可は不要ですが、public Bucket 内のオブジェクトをアップロードしたり削除したりする際には、適切なアクセス制御が必要になります。また、Public Bucket はパフォーマンスが向上する傾向があります。

https://youtu.be/4ERX__Y908k

summary

今回は、Supabase Storageに画像をアップロードしてみたいと思います。
やってることは単純だけど結構ハマりました😱

ルールの設定をする
作成しているBucketにルールを設定します。赤い丸がついている箇所のボタンを押していけば設定できます。


新しいルールを作成する

2番目の箇所を選択して、ボタンを押す

赤丸で囲んでいる箇所を全てチェックしてボタンを押す

画像をアップロードするソースコード
ログインした後のページで実行してます。

import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:supabase_gorouter/extention/push.dart';
import 'package:supabase_gorouter/screen/sign_in_page.dart';

class HomePage extends ConsumerStatefulWidget {
  const HomePage({super.key});

  static const rootName = '/home_page';

  
  ConsumerState<ConsumerStatefulWidget> createState() => _HomePageState();
}

class _HomePageState extends ConsumerState<HomePage> {
  bool isUploading = false;
  final supabase = Supabase.instance.client;

  Future<void> uploadFile() async {
    var pickedFile = await FilePicker.platform
        .pickFiles(allowMultiple: false, type: FileType.image);
    if (pickedFile != null) {
      setState(() {
        isUploading = true;
      });
      try {
        File file = File(pickedFile.files.single.path!);
        String fileName = pickedFile.files.first.name;
        String uploadUrl = await supabase.storage
            .from('profiles')
            .upload("${supabase.auth.currentUser!.id}/$fileName", file);
        setState(() {
          isUploading = false;
        });
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Uploaded $fileName'),
          ),
        );
      } catch (e) {
        print(e.toString());
        setState(() {
          isUploading = false;
        });
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Uploaded Error'),
          ),
        );
      }
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(actions: [
        IconButton(
          onPressed: () async {
            await supabase.auth.signOut();
            if (context.mounted) {
              await context.toAndRemoveUntil(const SignInPage());
            }
          },
          icon: const Icon(Icons.logout),
        )
      ], title: const Text('Home Page')),
      body: Center(
        child: Column(
          children: [
            IconButton(
                onPressed: () async {
                  await uploadFile();
                },
                icon: const Icon(Icons.upload))
          ],
        ),
      ),
    );
  }
}

アップロードに成功すると、画像がBucketに保存されます

thoughts

Firebase Storageは使ったことがあったのですが、Supabase Storageは使ったことがなくて、設定さえできていれば簡単に画像のアップロードができることを学べました。
Baasといえば、Firebaseが人気ですが、Supabaseも最近注目されているので、個人開発で使ってみたいな〜と思いました。

ConsumerStatefulWidgetを使用していますが、StatefulWidgetでもこのコードは使えます。ご興味ある方は、試してみてください。
ログインページはいらないかもしれません。

今回使用したパッケージ
https://pub.dev/packages/file_picker
https://pub.dev/packages/supabase_flutter

全体のコード
こちらに完成したソースコードのリンクを貼っておきます。
https://github.com/sakurakotubaki/SupabasePhotoApp

Discussion