メインコンテンツへスキップ

SupabaseでRLSを設定する方法|auth.uid()を使ったアクセス制御を解説

·1843 文字·4 分
目次

Supabaseでは認証を導入しただけでは十分ではありません。

ユーザーごとのデータアクセスを安全に制御するためには、 RLS(Row Level Security) の設定が必要です。

しかし、

  • RLSを有効化したらデータが取得できなくなった
  • auth.uid() がよくわからない
  • Policyの書き方がわからない

という人も多いのではないでしょうか。

この記事では、SupabaseでRLSを設定する方法を実際のSQL付きでわかりやすく解説します。


RLS設定が必要な理由
#

認証だけでは、

ログイン済みユーザー
postsテーブルへアクセス
他人のデータも取得できる

可能性があります。

そこで利用するのがRLSです。


RLSとは
#

RLS(Row Level Security)とは、

行(レコード)単位でアクセス制御を行うPostgreSQLの機能

です。

例えば以下のようなデータがあるとします。

user_idtitle
userA投稿A
userB投稿B

RLSを設定すると

  • userA → 投稿Aのみ取得可能
  • userB → 投稿Bのみ取得可能

になります。


RLSを有効化する
#

まず対象テーブルでRLSを有効にします。

ALTER TABLE posts
ENABLE ROW LEVEL SECURITY;

または

Table Editor
対象テーブル
Enable RLS

をONにします。


RLSを有効化するとどうなる?
#

実はRLSをONにしただけでは

誰もアクセスできない

状態になります。

つまり

SELECT * FROM posts;

を実行しても取得できません。


Policyとは
#

RLSでは

誰に何を許可するか

をPolicyで定義します。


SELECTを許可する
#

自分の投稿だけ取得可能にする例です。

CREATE POLICY "Users can view own posts"
ON posts
FOR SELECT
USING (
  auth.uid() = user_id
);

動作イメージ
#

ログインユーザー
auth.uid()
user_idと比較
一致した行だけ取得

auth.uid()とは
#

RLSで最も重要なのが

auth.uid()

です。

これは

現在ログインしているユーザーID

を取得する関数です。


JWTとの関係
#

内部では以下のように動いています。

ログイン
JWT発行
リクエスト送信
auth.uid()
Policy評価

つまり

auth.uid()

はJWTから取得されています。


INSERTを許可する
#

投稿作成を許可する場合。

CREATE POLICY "Users can insert own posts"
ON posts
FOR INSERT
WITH CHECK (
  auth.uid() = user_id
);

UPDATEを許可する
#

CREATE POLICY "Users can update own posts"
ON posts
FOR UPDATE
USING (
  auth.uid() = user_id
);

DELETEを許可する
#

CREATE POLICY "Users can delete own posts"
ON posts
FOR DELETE
USING (
  auth.uid() = user_id
);

USINGとWITH CHECKの違い
#

初心者が混乱しやすいポイントです。

USING
#

既存データへのアクセス制御

FOR SELECT
FOR UPDATE
FOR DELETE

で利用


WITH CHECK
#

新規データの検証

FOR INSERT

で利用


未ログインユーザーの扱い
#

未認証状態では

auth.uid()

NULL

になります。

つまり

auth.uid() = user_id

は常に偽になります。

結果として

  • 取得不可
  • 更新不可
  • 削除不可

になります。


全員に公開したい場合
#

ブログ記事などを全員が閲覧できるようにする場合。

CREATE POLICY "Public Posts"
ON posts
FOR SELECT
USING (true);

service_roleに注意(重要)
#

Supabase初心者が最もハマりやすいポイントです。


service_roleはRLSを無視する
#

サーバー側で利用する

SUPABASE_SERVICE_ROLE_KEY

はRLSをバイパスできます。

つまり

createClient(url, serviceRoleKey)

で実行すると

auth.uid() = user_id

は評価されません。


安全な運用
#

基本的には

ブラウザ
anon key

サーバー
service_role

で使い分けます。


RLSのパフォーマンス
#

RLSは内部的に

WHERE auth.uid() = user_id

のような条件として評価されます。

そのため

user_id

にはインデックスを付与しておくのがおすすめです。


推奨
#

CREATE INDEX idx_posts_user_id
ON posts(user_id);

大量データでは性能差が大きくなります。


よくあるミス
#

RLSをONにしただけ
#

RLS ON
Policyなし
何も取得できない

auth.uid()がNULL
#

原因

  • 未ログイン
  • JWT未送信

USINGとWITH CHECKを間違える
#

FOR INSERT

では

WITH CHECK

を使います。


service_roleでテストしてしまう
#

RLSが効いていると勘違いしやすいので注意です。


実務でのベストプラクティス
#

① RLSは必ずON
#

Supabaseでは基本必須です。


② auth.uid()を基本にする
#

auth.uid() = user_id

が最も一般的です。


③ service_roleはサーバー限定
#

クライアントへ公開しない。


④ user_idにインデックスを貼る
#

大量データで効果的です。


⑤ 本番前にポリシー確認
#

SELECT *
FROM pg_policies;

で確認できます。


まとめ
#

SupabaseでRLSを設定する流れは以下の通りです。

RLS有効化
Policy作成
auth.uid()でユーザー判定
アクセス制御

重要ポイント

  • RLSはDBレベルのアクセス制御
  • auth.uid()でユーザーを識別
  • JWTと連携して動作する
  • service_roleはRLSをバイパスする
  • user_idにはインデックスを付与する

👉 結論:Supabaseでは認証だけでなくRLSまで設定して初めて安全なアプリになる

著者
ゆーふー
Web開発、インフラ、AI技術に興味があるエンジニアです。日々の学びを記録しています。

関連記事

👤 運営者プロフィール

運営者プロフィール画像

ゆーふー

メガベンチャーで働く現役Webエンジニア(歴約2年)。
フロントエンドからインフラ構築、セキュリティ対策まで、実務で得た「現場のリアルな技術知見」を発信しています。