Chapter 2: 認証・認可設計 🔐
📚 目次に戻る: 📖 学習ガイド
⬅️ 前の章: Chapter 1: Supabaseアーキテクチャ理解
➡️ 次の章: Chapter 3: パターン1 - クライアントサイド実装
🎯 学習フェーズ: Part I - 基礎編(認証・認可)
🎯 学習レベル: 🌱 基礎 | 🚀 応用 | 💪 発展
⏱️ 推定学習時間: 3-4時間
📝 難易度: 基礎(セキュリティ概念の理解が重要)
—
🔄 前章の復習(Chapter 1からの継続)
Chapter 1で学んだSupabaseの3つの基本コンポーネントを振り返りましょう:
- ✅ PostgreSQL: データを安全に保存する倉庫
- ✅ PostgREST: データベースから自動でAPIを作成
- ✅ Realtime: データ変更をリアルタイムで通知
これらの基盤の上に、今度は「誰がアクセスできるか」「何をしていいか」を制御するセキュリティの仕組みを構築します。
💡 Chapter 1の理解度確認: PostgreSQL・PostgREST・Realtimeの役割を説明できますか?不安な場合はChapter 1を復習してください。
🎯 この章で学ぶこと(初心者向け)
この章では、「誰がアプリを使えるのか」「何ができるのか」 を管理する仕組みを学びます。
- 🌱 初心者: ログイン・ログアウトの基本的な仕組みがわかる
- 🚀 中級者: セキュリティを保つための具体的な方法がわかる
- 💪 上級者: 企業レベルのセキュリティシステムが設計できる
💡 身近な例から:「アパートの管理」に例えてみよう
Webアプリのセキュリティをアパートの管理に例えると理解しやすいです:
flowchart TD
A[🏠 アパート = あなたのWebアプリ] --> B[🚪 玄関 = ログイン画面]
B --> C{🔑 鍵チェック = 認証}
C -->|正しい鍵| D[✅ 入居者確認]
C -->|間違った鍵| E[❌ 入れません]
D --> F[🚪 各部屋 = 機能・データ]
F --> G{🔒 部屋の権限 = 認可}
G -->|自分の部屋| H[✅ 自由に使える]
G -->|他人の部屋| I[❌ 入れません]
G -->|共用部分| J[✅ みんなで使える]
用語説明:
- 🔑 認証(Authentication): 「あなたは誰ですか?」→ 身元確認
- 🔒 認可(Authorization): 「何をしていいですか?」→ 権限確認
🔑 Supabase Auth:「ログイン・ログアウトを簡単に」
🤔 従来のログイン機能作成:「大変な手作業」
普通、ログイン機能を作るのはとても大変でした:
📝 やることリスト(従来)
1. 📧 メールアドレス・パスワードの入力画面を作る
2. 🔒 パスワードを暗号化する仕組みを作る
3. 💾 ユーザー情報をデータベースに保存する
4. 🔐 ログイン状態を管理する仕組みを作る
5. 📱 「ログインしているかどうか」を各画面で確認する
6. 🔄 「ログイン期限切れ」の処理を作る
7. 📩 「パスワードを忘れた」機能を作る
8. 🛡️ セキュリティの穴がないかチェックする
9. 🐛 バグがないかテストする
10. 🚀 本番環境で安全に動くか確認する
時間: 数週間〜数ヶ月 😱
🔍 実際のコード例(Express.js)
// パスワード暗号化
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
// ユーザー登録(50行以上のコード)
app.post('/signup', async (req, res) => {
// バリデーション、重複チェック、暗号化...
// エラーハンドリング、データベース保存...
// メール認証、レスポンス作成...
});
// ログイン(40行以上のコード)
app.post('/login', async (req, res) => {
// 認証情報確認、パスワード照合...
// JWT生成、セッション管理...
});
// ログイン確認ミドルウェア(30行以上)
const authenticateToken = (req, res, next) => {
// トークン確認、期限チェック...
// ユーザー情報取得、権限確認...
};
// パスワードリセット(60行以上のコード)
// ... さらに続く
🎉 Supabase Authなら:「3行で完成」
// ユーザー登録
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'secure_password'
});
// ログイン
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'secure_password'
});
// ログアウト
const { error } = await supabase.auth.signOut();
時間: 数時間で完成! 🎉
🛡️ セキュリティも自動で完璧
Supabase Authが自動で処理してくれること:
セキュリティ機能 | 従来(手作業) | Supabase Auth |
---|---|---|
🔒 パスワード暗号化 | ⚠️ 自分で実装(ミスのリスク) | ✅ 自動で安全な暗号化 |
🕐 セッション管理 | ⚠️ 複雑な仕組みを自作 | ✅ 自動で期限管理 |
📧 メール認証 | ⚠️ メール送信の仕組みを構築 | ✅ 自動でメール送信 |
🔄 パスワードリセット | ⚠️ 安全な仕組みを設計 | ✅ 自動で安全な仕組み |
🛡️ 攻撃対策 | ⚠️ セキュリティの穴を自分で塞ぐ | ✅ 業界標準の対策を自動実装 |
🚀 いろいろなログイン方式も対応済み
// 📧 メール・パスワード
await supabase.auth.signInWithPassword({...});
// 🔗 Magic Link(パスワード不要)
await supabase.auth.signInWithOtp({
email: 'user@example.com'
});
// 🌐 Google ログイン
await supabase.auth.signInWithOAuth({
provider: 'google'
});
// 📱 電話番号
await supabase.auth.signInWithOtp({
phone: '+81901234567'
});
従来の認証実装との違い
項目 | Supabase Auth | 自前実装 | Firebase Auth | Auth0 |
---|---|---|---|---|
実装時間 | ✅ 数時間 | ❌ 数週間 | ✅ 数時間 | ✅ 数時間 |
セキュリティ | ✅ 企業級 | ⚠️ 実装依存 | ✅ 企業級 | ✅ 企業級 |
カスタマイズ性 | ✅ 高い | ✅ 完全制御 | ⚠️ 限定的 | ✅ 高い |
コスト | ✅ 低コスト | ❌ 開発・運用コスト | ⚠️ 従量課金 | ❌ 高コスト |
DB統合 | ✅ 完全統合 | ⚠️ 手動実装 | ❌ 別システム | ❌ 別システム |
自前実装の課題解決例:
// 従来の自前実装(Express.js + bcrypt)
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
app.post('/auth/signup', async (req, res) => {
try {
// 1. バリデーション(手動実装が必要)
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ error: 'Email and password required' });
}
// 2. 重複チェック(手動実装が必要)
const existingUser = await db.query('SELECT * FROM users WHERE email = ?', [email]);
if (existingUser.length > 0) {
return res.status(400).json({ error: 'User already exists' });
}
// 3. パスワードハッシュ化(手動実装が必要)
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
// 4. ユーザー作成(手動実装が必要)
const userId = uuid.v4();
await db.query('INSERT INTO users (id, email, password) VALUES (?, ?, ?)',
[userId, email, hashedPassword]);
// 5. メール認証(手動実装が必要)
const confirmationToken = jwt.sign({ userId }, EMAIL_SECRET, { expiresIn: '24h' });
await sendConfirmationEmail(email, confirmationToken);
// 6. レスポンス
res.status(201).json({ message: 'Please check your email' });
} catch (error) {
console.error('Signup error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// ログイン機能も同様に数十行の実装が必要...
// Supabase Auth(自動実装)
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'secure_password'
});
// → バリデーション、重複チェック、ハッシュ化、メール認証が自動実行
// → 実装コードが95%削減
JWT構造とSupabase固有クレーム
Supabase AuthはJWT RFC 7519準拠のトークンを生成し、PostgreSQL RLSとの統合を最適化した独自クレームを含みます。
標準クレーム:
{
"iss": "https://your-project.supabase.co/auth/v1",
"sub": "user-uuid",
"aud": "authenticated",
"exp": 1640995200,
"iat": 1640908800,
"email": "user@example.com",
"phone": "+1234567890"
}
Supabase固有クレーム:
{
"app_metadata": {
"provider": "email",
"providers": ["email"]
},
"user_metadata": {
"display_name": "John Doe",
"avatar_url": "https://..."
},
"role": "authenticated",
"session_id": "session-uuid"
}
認証フロー実装
1. Email/Password認証
sequenceDiagram
participant C as Client
participant SA as Supabase Auth
participant DB as PostgreSQL
C->>SA: POST /auth/v1/signup
SA->>DB: INSERT INTO auth.users
SA->>SA: 確認メール送信
SA-->>C: 201 Created
C->>SA: GET /auth/v1/verify
SA->>DB: UPDATE auth.users SET email_confirmed_at
SA->>SA: JWT生成
SA-->>C: 302 Redirect + Set-Cookie
サインアップ実装:
-- auth.users テーブル構造
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'auth' AND table_name = 'users';
-- パスワードハッシュ化(bcrypt)
INSERT INTO auth.users (
id, email, encrypted_password,
email_confirmed_at, created_at, updated_at
) VALUES (
uuid_generate_v4(),
'user@example.com',
crypt('password', gen_salt('bf')),
NOW(), NOW(), NOW()
);
2. OAuth実装
// GoTrue内部実装(概念的)
interface OAuthProvider {
name: string;
authorize_url: string;
token_url: string;
user_info_url: string;
}
class GoogleProvider implements OAuthProvider {
async exchangeCodeForToken(code: string): Promise<OAuthToken> {
const response = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: this.clientId,
client_secret: this.clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: this.redirectUri
})
});
return response.json();
}
}
JWT検証とミドルウェア
PostgRESTでのJWT検証:
-- PostgREST内部実装(Haskell)
verifyJWT :: ByteString -> JWTSecret -> Either JWTError JWTClaims
verifyJWT token secret = do
jwt <- decodeCompact token
verifyClaims defaultJWTValidationSettings (view claimsSet jwt)
extractRole :: JWTClaims -> Maybe Role
extractRole claims =
claims ^? claimSub . _Just . to parseRole
カスタムJWT検証関数:
-- PostgreSQL内カスタム関数
CREATE OR REPLACE FUNCTION auth.jwt_role()
RETURNS TEXT AS $$
SELECT COALESCE(
current_setting('request.jwt.claims', true)::json->>'role',
'anon'
);
$$ LANGUAGE sql STABLE;
CREATE OR REPLACE FUNCTION auth.uid()
RETURNS UUID AS $$
SELECT COALESCE(
current_setting('request.jwt.claims', true)::json->>'sub',
'00000000-0000-0000-0000-000000000000'
)::uuid;
$$ LANGUAGE sql STABLE;
2.2 RLSポリシー設計パターン
階層的アクセス制御
-- 組織階層テーブル設計
CREATE TABLE organizations (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
parent_id BIGINT REFERENCES organizations(id),
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE user_org_memberships (
user_id UUID REFERENCES auth.users(id),
org_id BIGINT REFERENCES organizations(id),
role org_role_type NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (user_id, org_id)
);
-- カスタム型定義
CREATE TYPE org_role_type AS ENUM (
'owner', 'admin', 'member', 'viewer'
);
継承的ポリシー
-- 再帰CTEによる階層アクセス
CREATE OR REPLACE FUNCTION user_accessible_orgs(user_uuid UUID)
RETURNS TABLE(org_id BIGINT, effective_role org_role_type) AS $$
WITH RECURSIVE org_hierarchy AS (
-- 直接メンバーシップ
SELECT
m.org_id,
m.role,
0 as depth
FROM user_org_memberships m
WHERE m.user_id = user_uuid
UNION ALL
-- 子組織への継承
SELECT
o.id as org_id,
h.role,
h.depth + 1
FROM organizations o
JOIN org_hierarchy h ON o.parent_id = h.org_id
WHERE h.depth < 10 -- 無限ループ防止
)
SELECT DISTINCT ON (org_id)
org_id,
role as effective_role
FROM org_hierarchy
ORDER BY org_id, depth ASC; -- より近い階層の権限を優先
$$ LANGUAGE sql STABLE;
-- 階層ポリシー適用
CREATE POLICY "Hierarchical access" ON documents
FOR ALL USING (
EXISTS (
SELECT 1 FROM user_accessible_orgs(auth.uid())
WHERE org_id = documents.org_id
)
);
時間ベースアクセス制御
-- 時限付きアクセス
CREATE TABLE temp_access_grants (
id BIGSERIAL PRIMARY KEY,
user_id UUID REFERENCES auth.users(id),
resource_id BIGINT,
resource_type TEXT,
permissions TEXT[],
valid_from TIMESTAMPTZ DEFAULT NOW(),
valid_until TIMESTAMPTZ NOT NULL,
created_by UUID REFERENCES auth.users(id)
);
CREATE POLICY "Temporary access" ON sensitive_documents
FOR SELECT USING (
owner_id = auth.uid() OR
EXISTS (
SELECT 1 FROM temp_access_grants tag
WHERE tag.user_id = auth.uid()
AND tag.resource_id = sensitive_documents.id
AND tag.resource_type = 'sensitive_document'
AND 'read' = ANY(tag.permissions)
AND NOW() BETWEEN tag.valid_from AND tag.valid_until
)
);
属性ベースアクセス制御 (ABAC)
-- ユーザー属性テーブル
CREATE TABLE user_attributes (
user_id UUID REFERENCES auth.users(id),
attribute_name TEXT NOT NULL,
attribute_value TEXT NOT NULL,
valid_until TIMESTAMPTZ,
PRIMARY KEY (user_id, attribute_name)
);
-- 動的ポリシー関数
CREATE OR REPLACE FUNCTION check_user_attribute(
user_uuid UUID,
attr_name TEXT,
required_value TEXT
) RETURNS BOOLEAN AS $$
SELECT EXISTS (
SELECT 1 FROM user_attributes
WHERE user_id = user_uuid
AND attribute_name = attr_name
AND attribute_value = required_value
AND (valid_until IS NULL OR valid_until > NOW())
);
$$ LANGUAGE sql STABLE;
-- ABAC適用例
CREATE POLICY "Department access" ON financial_reports
FOR SELECT USING (
check_user_attribute(auth.uid(), 'department', 'finance') OR
check_user_attribute(auth.uid(), 'clearance_level', 'executive')
);
ポリシー最適化
インデックス戦略:
-- RLSクエリ最適化用複合インデックス
CREATE INDEX idx_user_org_memberships_lookup
ON user_org_memberships (user_id, org_id)
INCLUDE (role);
-- 部分インデックス
CREATE INDEX idx_active_temp_grants
ON temp_access_grants (user_id, resource_id, resource_type)
WHERE valid_until > NOW();
-- GIN インデックス(配列検索用)
CREATE INDEX idx_permissions_gin
ON temp_access_grants USING gin(permissions);
パフォーマンス測定:
-- ポリシー実行時間測定
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT * FROM documents WHERE title ILIKE '%budget%';
-- RLS無効化での比較
SET row_security = off;
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM documents WHERE title ILIKE '%budget%';
SET row_security = on;
2.3 組織・ロールベースアクセス制御実装
多テナント設計パターン
1. Row-based Multi-tenancy
-- 全テーブルにtenant_id追加
CREATE TABLE projects (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id),
name TEXT NOT NULL,
description TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- テナント分離ポリシー
CREATE POLICY "Tenant isolation" ON projects
FOR ALL USING (
tenant_id IN (
SELECT t.id FROM tenants t
JOIN user_tenant_memberships utm ON t.id = utm.tenant_id
WHERE utm.user_id = auth.uid()
)
);
2. Schema-based Multi-tenancy
-- 動的スキーマ作成
CREATE OR REPLACE FUNCTION create_tenant_schema(tenant_name TEXT)
RETURNS VOID AS $$
DECLARE
schema_name TEXT := 'tenant_' || tenant_name;
BEGIN
-- スキーマ作成
EXECUTE format('CREATE SCHEMA %I', schema_name);
-- テーブル作成
EXECUTE format('
CREATE TABLE %I.projects (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
)', schema_name);
-- RLS有効化
EXECUTE format('ALTER TABLE %I.projects ENABLE ROW LEVEL SECURITY', schema_name);
END;
$$ LANGUAGE plpgsql;
高度な権限モデル
リソースベース権限:
-- 権限定義テーブル
CREATE TABLE permissions (
id BIGSERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
description TEXT,
resource_type TEXT NOT NULL
);
-- ロール-権限マッピング
CREATE TABLE role_permissions (
role_id BIGINT REFERENCES roles(id),
permission_id BIGINT REFERENCES permissions(id),
PRIMARY KEY (role_id, permission_id)
);
-- 動的権限チェック関数
CREATE OR REPLACE FUNCTION user_has_permission(
user_uuid UUID,
permission_name TEXT,
resource_id BIGINT DEFAULT NULL
) RETURNS BOOLEAN AS $$
BEGIN
RETURN EXISTS (
SELECT 1
FROM user_role_assignments ura
JOIN role_permissions rp ON ura.role_id = rp.role_id
JOIN permissions p ON rp.permission_id = p.id
WHERE ura.user_id = user_uuid
AND p.name = permission_name
AND (resource_id IS NULL OR ura.resource_id = resource_id)
AND ura.valid_from <= NOW()
AND (ura.valid_until IS NULL OR ura.valid_until > NOW())
);
END;
$$ LANGUAGE plpgsql STABLE;
監査とコンプライアンス
操作ログテーブル:
CREATE TABLE audit_logs (
id BIGSERIAL PRIMARY KEY,
user_id UUID REFERENCES auth.users(id),
action TEXT NOT NULL,
resource_type TEXT NOT NULL,
resource_id BIGINT,
old_values JSONB,
new_values JSONB,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 監査トリガー関数
CREATE OR REPLACE FUNCTION audit_trigger_function()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_logs (
user_id, action, resource_type, resource_id,
old_values, new_values, ip_address
) VALUES (
auth.uid(),
TG_OP,
TG_TABLE_NAME,
COALESCE(NEW.id, OLD.id),
CASE WHEN TG_OP = 'DELETE' THEN to_jsonb(OLD) ELSE NULL END,
CASE WHEN TG_OP IN ('INSERT', 'UPDATE') THEN to_jsonb(NEW) ELSE NULL END,
COALESCE(
current_setting('request.headers', true)::json->>'x-forwarded-for',
'0.0.0.0'
)::inet
);
RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;
-- トリガー適用
CREATE TRIGGER audit_trigger_projects
AFTER INSERT OR UPDATE OR DELETE ON projects
FOR EACH ROW EXECUTE FUNCTION audit_trigger_function();
セキュリティヘッダーとCSP
Kong設定での追加:
# kong.yml
_format_version: "2.1"
services:
- name: supabase-auth
url: http://supabase-auth:9999
routes:
- name: auth-route
paths: ["/auth/v1/"]
strip_path: true
plugins:
- name: response-transformer
config:
add:
headers:
- "X-Content-Type-Options: nosniff"
- "X-Frame-Options: DENY"
- "X-XSS-Protection: 1; mode=block"
- "Strict-Transport-Security: max-age=31536000; includeSubDomains"
- "Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'"
実装例: エンタープライズSaaS認可システム
-- 完全な認可システム実装
CREATE SCHEMA authorization;
-- 基本エンティティ
CREATE TABLE authorization.tenants (
id BIGSERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
plan subscription_plan_type NOT NULL,
max_users INTEGER NOT NULL,
features TEXT[] NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE authorization.roles (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT REFERENCES authorization.tenants(id),
name TEXT NOT NULL,
is_system_role BOOLEAN DEFAULT FALSE,
permissions JSONB NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(tenant_id, name)
);
-- 統合認可チェック関数
CREATE OR REPLACE FUNCTION authorization.check_access(
user_uuid UUID,
action TEXT,
resource_type TEXT,
resource_id BIGINT DEFAULT NULL,
tenant_context BIGINT DEFAULT NULL
) RETURNS BOOLEAN AS $$
DECLARE
user_tenant_id BIGINT;
user_roles BIGINT[];
required_permission TEXT;
BEGIN
-- テナントコンテキスト取得
user_tenant_id := COALESCE(
tenant_context,
(SELECT tenant_id FROM authorization.user_tenants
WHERE user_id = user_uuid LIMIT 1)
);
-- ユーザーロール取得
SELECT array_agg(role_id) INTO user_roles
FROM authorization.user_role_assignments
WHERE user_id = user_uuid
AND tenant_id = user_tenant_id
AND NOW() BETWEEN valid_from AND COALESCE(valid_until, 'infinity');
-- 権限チェック実行
required_permission := resource_type || ':' || action;
RETURN EXISTS (
SELECT 1 FROM authorization.roles r
WHERE r.id = ANY(user_roles)
AND r.permissions ? required_permission
AND CASE
WHEN resource_id IS NOT NULL THEN
r.permissions->>required_permission @> '{"scope": "all"}' OR
r.permissions->>required_permission @> format('{"resources": [%s]}', resource_id)
ELSE TRUE
END
);
END;
$$ LANGUAGE plpgsql STABLE;
まとめ
認証・認可システムの設計では、セキュリティと実装効率のバランスが重要です。RLSによる多層防御と、柔軟な権限モデルの組み合わせにより、エンタープライズレベルの要件に対応できます。
設計原則:
- 最小権限の原則: 必要最小限の権限のみ付与
- 深層防御: 複数レイヤーでのセキュリティチェック
- 監査可能性: すべての操作の追跡可能性確保
- パフォーマンス考慮: インデックス戦略による最適化
📝 Chapter 2 学習まとめ
📊 学習進捗トラッキング
この章の学習進捗を以下のチェックリストで確認してください:
🌱 基礎理解(必須)
- 認証(Authentication)と認可(Authorization)の違いを説明できる
- JWT(JSON Web Token)の基本的な仕組みを理解した
- RLS(Row Level Security)によるデータアクセス制御の概念を理解した
- Supabase Authの基本的な機能(サインアップ・ログイン)を理解した
🚀 応用理解(推奨)
- ロールベースアクセス制御(RBAC)の設計パターンを理解した
- 組織・テナント単位での権限管理設計を理解した
- RLSポリシーの具体的な作成・適用方法を理解した
- JWT Claimsとカスタムクレームの活用方法を理解した
💪 発展理解(上級者向け)
- 複雑な組織階層・権限継承システムの設計ができる
- セキュリティ脅威(SQL Injection・XSS・CSRF等)と対策を理解した
- パフォーマンスを考慮したRLSポリシー・インデックス設計ができる
- OAuth・SAML等の外部認証プロバイダー連携を理解した
🔧 実践スキル(確認推奨)
- Supabase Authを使った基本的な認証フローを実装できる
- テーブルにRLSを有効化し、基本的なポリシーを作成できる
- JWT トークンの確認・デバッグができる
- 認証エラーの基本的なトラブルシューティングができる
✅ 習得できたスキル
- ✅ JWT認証・Supabase Auth による安全なユーザー管理
- ✅ RLS(Row Level Security)による行レベルアクセス制御
- ✅ ロールベース・組織ベース認可システム設計
- ✅ セキュリティとパフォーマンスを両立する実装手法
🎯 認証・認可の重要ポイント
| 概念 | 説明 | 実際の例 | |:—–|:—–|:———:| | 認証 (Authentication) | 「あなたは誰ですか?」の確認 | ログイン・パスワード確認 | | 認可 (Authorization) | 「何をしていいですか?」の制御 | 管理者のみ削除可能など | | RLS | データベースレベルでの自動制御 | 作成者のみが自分のデータ操作可能 | | JWT | 安全なセッション管理 | ログイン状態の維持・API認証 |
🔄 次章への準備
Chapter 3で学ぶクライアントサイド実装の前提知識:
- ✅ ユーザー認証の流れ理解(サインアップ・ログイン・ログアウト)
- ✅ RLSの基本概念理解(誰がどのデータにアクセス可能か)
- ✅ JWT の役割理解(安全なAPI呼び出しの仕組み)
💡 実践演習
🌱 基礎演習(必須)
-
概念確認: 認証(Authentication)と認可(Authorization)の違いを具体例で説明してください
-
RLS設計: 以下のシナリオでRLSポリシーを設計してください
- テーブル:
documents
(文書管理) - 要件: 作成者のみが自分の文書を表示・編集できる
- テーブル:
🚀 応用演習(推奨)
- 権限設計: 以下の組織でのロールベース権限設計を考えてください
- 組織: 中小企業(部長・課長・一般社員)
- システム: 経費申請・承認システム
- 要件: 階層的な承認フロー
- セキュリティ分析: パスワード認証の脆弱性と、それに対するSupabaseの対策をまとめてください
💪 発展演習(上級者向け)
- 複雑権限実装: マルチテナント(複数企業)での複雑な権限システムを設計してください
- 企業A・Bのデータは完全分離
- 企業内での部署・役職による細かい権限制御
- 実装演習: Supabase Studioで実際に以下を実装してください
- ユーザーテーブル
- RLSポリシー
- 基本的な認証フロー
📝 演習の解答例・解説
解答例を確認(クリックして展開)
**1. 概念確認の解答例** - **認証**: 「あなたは誰ですか?」の確認(例:ログイン・パスワード入力) - **認可**: 「何をする権限がありますか?」の制御(例:管理者のみ削除可能) **2. RLS設計の解答例** ```sql -- RLS有効化 ALTER TABLE documents ENABLE ROW LEVEL SECURITY; -- 作成者のみアクセス可能 CREATE POLICY "Own documents only" ON documents FOR ALL USING (auth.uid() = user_id); ```🚀 次章予告:クライアントサイド実装
Chapter 3では、「診療所の電子カルテシステム」を例に、実践的なアプリケーション開発を学習します:
- 🖥️ Python Flet UI: デスクトップアプリライクな直感的インターフェース
- 📋 タスク管理機能: 患者予約・診療記録・進捗管理システム
- 🔐 認証統合: Chapter 2で学んだ認証機能の実装適用
- ⚡ リアルタイム: 複数スタッフでの同時作業・即座の情報共有
💡 実装目標: 「病院スタッフが使いやすく、患者情報も安全に管理できるシステム」
📋 次章に向けた準備課題
Chapter 3のクライアントサイド実装をスムーズに進めるために、以下を確認・準備してください:
必須準備
- Supabaseプロジェクト作成済み(無料アカウントでOK)
- 基本的なSQL操作の理解(CREATE TABLE、INSERT、SELECT)
- JWT の概念理解(トークンベース認証の仕組み)
推奨準備
- Python基礎知識(変数・関数・クラスの基本)
- 簡単なRLSポリシーの作成経験
- Supabase Studio の基本操作に慣れている
準備が不安な場合
- 🔍 Supabase公式チュートリアル を実施
- 📚 付録:環境構築 で開発環境を準備
- 💬 不明点は GitHub Discussions で質問
📍 ナビゲーション
- 📚 目次: 📖 学習ガイド
- ⬅️ 前の章: Chapter 1: Supabaseアーキテクチャ理解
- ➡️ 次の章: Chapter 3: クライアントサイド実装
-
🏠 関連章: Chapter 7: セキュリティ強化 全体設計 -
🔧 リソース: 認証テンプレート セキュリティ・ガイド