Supabase RLS で安全な有料コンテンツゲートを作る — 設計パターンと実装の落とし穴
なぜ RLS が「ペイウォール」の核心なのか
有料コンテンツを配信するサービスで、最も恐ろしいのは何か。
「お金を払っていない人がコンテンツを見られる」状態。
クライアント側で if (purchased) { showContent() } のように制御していると、JavaScript を無効化したり、API を直接叩いたりするだけで突破される。
サーバー側でチェックしても、「全ユーザーの購入履歴テーブル」をうっかり全件取得できる API を作ってしまえば終わり。
Supabase Row Level Security(RLS)は、この問題をデータベース層で解決する。
データベース自体が「このユーザーはこの行を見れる/見れない」を判定するため、アプリケーション側のバグでは突破できない。
このブログの有料記事機能も、RLS を有効にしています。仮に Next.js 側のチェックロジックにバグがあっても、データベース層でブロックされる二重の防御が効きます。
この記事でわかること:
- RLS の基本概念と「2層防御」の設計思想
- 購入履歴テーブルの RLS ポリシー設計
- Service Role Key と Anon Key の使い分け
- Webhook からの書き込みで RLS をバイパスする正しい方法
- N+1 問題を避ける購入チェックの実装
- サーバーコンポーネントでの効率的な使い方
RLS の基本: 「行レベル」のアクセス制御
通常のテーブル権限は「テーブル全体」に対して付与する。
GRANT SELECT ON article_purchases TO authenticated;
これだと、認証済みユーザーは全員の購入履歴を見れてしまう。
RLS は「どの行を見れるか」を SQL で記述できる。
ALTER TABLE article_purchases ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view own purchases"
ON article_purchases
FOR SELECT
USING (auth.uid() = user_id);
これで、Supabase 経由のクエリは自動的に WHERE user_id = '現在のユーザーID' がついた状態で実行される。
別のユーザーの購入履歴を取得しようとしても、結果は空になる。
関連記事
Next.js + Supabase 個人開発入門2026
無料枠だけでSaaSを作る構成と実装手順を解説
Stripe × Next.js 決済導入ガイド2026
個人開発で売上を立てるまでのStripe実装手順を全公開
個人開発の認証実装完全ガイド
Clerk・Supabase Auth・NextAuthの比較と選び方を解説
Claude Code で副業を始める 6ステップ — 無料
環境構築から最初の売上まで、週1配信で学べる無料メール講座。登録で「収益化チェックリスト 15 項目」もプレゼント。
副業6ステップ講座(無料)
記事の続きを読むには購入が必要です
この記事が役に立ったらシェア