前回の続き——認証の次は「認可の実装」

前回のQ-04では、認証を外部サービスに委ねる外部ログインを学びました。認証は誰であるかの確認でしたが、この講義が扱うのはその先、ログインした人が何をしてよいかを判断する認可の実装です。認可そのものはQ-01で定義しました。ここではその認可を、実際にどの単位で制御するのかを、三つの粒度に分けて具体化していきます。この三つを押さえることが、安全な認可づくりの土台になります。

このスライドのポイント

  • 前回Q-04: 認証を外部サービスに委ねる外部ログインを学んだ
  • 認証=誰であるかの確認。今回はその先、認可=何をしてよいかの判断の実装
  • 認可はQ-01で定義済み。今回はそれを「どの単位で制御するか」に具体化する

認可の実装3粒度

認可の実装には、粗いものから細かいものへ三つの粒度があります。一つ目はロールで、申請者・承認者・経理・管理者といった役割単位の制御です。これはA-08で決めた権限の役割表を、正式なかたちにしたものです。二つ目は操作権限で、承認できる、出力できるといった機能単位の制御です。三つ目はRLS、Row Level Securityの略で、データの行、つまりL-03で見た一件一件の単位で制御する仕組みです。自分のuser_idの行だけが見える、という規則をデータベース層で強制します。

このスライドのポイント

  • 認可(Q-01)の実装には粗い順に3つの粒度がある
  • ①ロール=役割単位(申請者/承認者/経理/管理者。A-08の権限の役割表の正式化)
  • ②操作権限=機能単位(承認できる/出力できる)
  • ③RLS(Row Level Security)=データの行(L-03)単位(「自分のuser_idの行だけ見える」をDB層で強制)
  • RLSは参照スタックのPostgreSQL/Supabaseが備える

なぜ行単位の制御が要るのか

三つ目の行単位の制御を軽視すると、どうなるでしょうか。よくある事故が、一覧を返すAPIにログインは必要だけれど、絞り込みが無いために全社員の申請が返ってしまう、という形です。認可はあるのに、粒度が粗いのです。問題は、アプリ側のコードで絞り込みを一箇所書き忘れるだけで漏えいになる点です。だからこそ、データベース層で強制するRLSは、アプリの絞り込み忘れへの保険、つまり最後の砦になります。

このスライドのポイント

  • よくある事故: 一覧APIにログインは必要だが、絞り込みが無く全社員の申請が返る
  • 認可はあるのに粒度が粗い状態
  • アプリ側のコードで絞り込みを1箇所書き忘れるだけで漏えいになる
  • だからDB層で強制するRLSは、アプリの絞り込み忘れへの保険(最後の砦)

構造——3粒度のピラミッドとRLSの位置づけ

三つの粒度は、ロールを土台に、その上に操作、さらに上に行という階層で捉えると整理できます。上にいくほど、制御は細かくなります。ここで思い出してほしいのが、L-09で学んだ、データベースの制約は最後の砦だという考え方です。RLSは、その考え方を認可に当てはめたものだと言えます。アプリ側の判断がすべてすり抜けてしまっても、最後にデータベースが他人の行を渡さない、という守りの層になるのです。

このスライドのポイント

  • 3粒度はロールを土台に、操作、行と積み上がるピラミッド
  • 上にいくほど制御は細かくなる
  • L-09「DBの制約=最後の砦」の認可版がRLS
  • アプリ側の判断が全てすり抜けても、最後にDBが他人の行を渡さない層

経費アプリでの動き

経費アプリで具体的に見ます。申請を保存するexpensesテーブルに、user_idがログイン中のユーザーのIDと一致する行だけを見せる、というRLSの規則を設定します。こうしておくと、アプリのコードが一覧取得のときに絞り込みのWHEREを書き忘れても、あるいはP-03で扱った異常系のように想定外の動きをしても、データベースが他人の行を返しません。RLSがある限り、同じ問い合わせであっても、利用者ごとに見える行が変わるのです。

このスライドのポイント

  • expensesテーブルに「user_id = ログイン中のユーザーのID の行のみ可視」の規則
  • アプリのコードが絞り込みのWHEREを書き忘れても、DBが他人の行を返さない
  • P-03の異常系のような想定外でも、行の壁は保たれる
  • 同じ問い合わせでも、利用者ごとに見える行が変わる

技術サンプルカード

サンプルは、認可の3粒度とRLSの働きを一枚にまとめた図です。上の表は、役割・操作・行という三つの制御単位を、粗い順に並べています。下の図が要点で、同じSELECTという一つの命令であっても、誰がログインしているかによって返る行が変わることを示しています。読み方のポイントは、この絞り込みがアプリのコードではなく、データベース層で強制されている点です。AIには、認可を3粒度で整理させ、行単位の制御をアプリとDBのどちらで強制しているかを確かめてもらいましょう。

混同しやすい概念——アプリ側の絞り込みとRLS

混同しやすいのが、アプリ側の絞り込みとRLSの違いです。アプリ側の絞り込みは、コードのなかでWHEREを書いて他人の行を除くやり方で、書き忘れが起こりえます。一方RLSは、データベース層で強制されるので、コードが忘れても守られます。どちらか一方ではなく、両方あるのが理想です。ふだんはアプリ側で絞り込み、それでも漏れたときにRLSが保険として効く、という二重の守りを目指してください。

バイブコーディングでの確認点

バイブコーディングで確認すべきことです。個人データを持つテーブルには、必ずRLSが有効になっているか、そしてどんな規則かを確かめてください。参照スタックのSupabaseでは、RLSの設定忘れが最も多い事故の一つです。AIにコードを作らせたら、このアプリで個人データを持つテーブルにRLSは有効ですか、それぞれどの規則で行を絞っていますか、と質問しましょう。有効でなければ、その理由と対策を必ず確認してください。

このスライドのポイント

  • 個人データを持つテーブルには「RLSは有効か/どの規則か」を必ず確認
  • 参照スタックのSupabaseではRLSの設定忘れが最頻出の事故
  • AIへの質問例:「個人データを持つテーブルにRLSは有効ですか。それぞれどの規則で行を絞っていますか」
  • 有効でなければ理由と対策を確認する

まとめと一問一答

最後に一問一答です。行単位でアクセスを制御するデータベースの仕組みを、何と呼ぶでしょうか。……答えは、RLS、Row Level Securityです。30秒まとめとして、認可にはロール・操作・行の三つの粒度があり、行単位の制御はアプリ側の絞り込みだけに頼らず、RLSでデータベース層に保険をかけることが要点でした。次回のQ-06では、そもそも入力を信用しないという、防御のもう一つの大原則へ進みます。関連資料は「Supabase RLS入門」「権限設計の基本パターン集」です。

このスライドのポイント

  • 一問一答: 行単位でアクセスを制御するDBの仕組みは? → RLS(Row Level Security)
  • 30秒まとめ: 認可は「ロール・操作・行」の3粒度/行単位はアプリの絞り込みだけに頼らずRLSでDBに保険
  • 次回Q-06: 入力を信用しないという原則へ
  • 関連資料: 「Supabase RLS入門」「権限設計の基本パターン集」