ハンズオン
認証と管理者ロール
読み取り専用/読み取り+操作の管理者ロールをDBで管理し、管理APIを保護し、このテンプレートの認証パイプラインを説明します。
認証と管理者ロール
このテンプレートは Better Auth + Drizzle を使用します。RBAC はデータベースに保存し、環境変数での昇格は行いません。
基本: 認証と認可の違い
- 認証 (Authentication): 誰かを確認する(サインアップ/サインイン)。結果としてセッションが得られます。
- 認可 (Authorization): その後に何ができるかを決める。このテンプレートでは
usersテーブルのroleが制御します。
ロール:
user— すべてのユーザーの既定。admin_ro— 読み取り専用(管理データの閲覧のみ)。admin_rw— 読み取り + 書き込み(クレジット付与などの管理操作を含む)。
空港のアナロジー
保安検査で身分証を提示するのが「認証」(本人確認)。搭乗口で搭乗券を提示するのが「認可」(その便に乗れるかの確認)。
クイック比較
| 項目 | 認証 | 認可 |
|---|---|---|
| 目的 | 身元の確認(誰か) | 権限の確認(何ができるか) |
| タイミング | 認可より前 | 認証が成功した後 |
| 典型入力 | 資格情報(パスワード、メールリンク、ソーシャル) | ポリシー/ロール(user、admin_ro、admin_rw) |
| 出力 | セッション/アイデンティティ | 許可された操作と保護されたルート |
| 一般的な標準 | OIDC、ID トークン | OAuth 2.0、スコープ |
本テンプレートでは、フロントのトークンではなくサーバーの HttpOnly セッションクッキーを使用し、DB 上の role で認可を行います。
Better Auth とは?
Next.js 向けの軽量で TypeScript ファーストな認証ライブラリです。
- ストレージ: Drizzle ORM + Postgres(
src/lib/auth.tsを参照)。 - データモデル:
users、sessions、accounts、verifications(src/db/schema.ts)。 - セッション: HttpOnly クッキー +
sessionsテーブルに保存。サーバールートはauth.api.getSession({ headers })で読み取ります。 - 追加フィールド:
additionalFieldsでuuidとroleをセッションに含め、サーバー側のチェックを簡単にします。
シークレットと URL(入門)
BETTER_AUTH_SECRET: 認証用のクッキー/トークンに署名・検証するサーバー専用の長い乱数文字列。1 回生成して安全に保管します。- 生成:
openssl rand -base64 32 - ローテーション: 値を変更すると全ユーザーがサインアウトされます(既存セッションが無効に)。
- 生成:
BETTER_AUTH_URL: 認証ライブラリが使用するサーバーのベース URL(通常はサイト URL)。NEXT_PUBLIC_AUTH_BASE_URL: クライアント側のベース(多くの場合サイト URL と同じ)。- クッキーは本番で
HttpOnlyかつsecure(src/lib/auth.tsのadvanced.defaultCookieAttributesを参照)。
サインインが 1 回しか動かない/再起動でセッションが消える場合は、上記の環境変数を確認して dev サーバーを再起動してください。
ロール
user: 既定ロール。admin_ro: 読み取り専用。ユーザー/注文の一覧、ユーザーのクレジット閲覧。admin_rw: 読み取り+操作。system_addでクレジット付与も可能。
マイグレーション 0001_add_user_role.sql で users.role(既定値 user)を追加します。
認可
src/lib/authz.tsがセッション/DB からロールを取得します:requireAdminRead()→admin_ro/admin_rwを許可。requireAdminWrite()→admin_rwを許可。
管理API
GET /api/admin/users→ ユーザー一覧(page,limit)。GET /api/admin/orders→ 支払い済み注文(ページング)。GET /api/admin/users/:uuid/credits→ クレジット要約。POST /api/admin/credits/grant→system_addでクレジット付与。
セットアップ手順
- DB をマイグレーション:
pnpm drizzle-kit migrate --config src/db/config.ts- 管理アカウントでエンドポイントを確認。
ロールの変更方法
権威は DB 側に持たせます:
- SQL:
update users set role = 'admin_rw' where uuid = '<uuid>'; - ヘルパー:
updateUserRole(uuid, 'admin_ro' | 'admin_rw' | 'user')(src/models/user.ts)。
注意
- 管理アカウントは MFA/SSO と短いセッション期限を推奨。
- 管理ページはサーバー側でチェックし、未認可はリダイレクト。
- ロールは .env では管理しません。DB で設定/解除します。
ソーシャルログイン(Google)
- Google プロバイダは
src/lib/auth.tsのsocialProviders.googleで設定され、.envのGOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRETを参照します。 .envにGOOGLE_CLIENT_ID、GOOGLE_CLIENT_SECRETを設定し、BETTER_AUTH_URLとNEXT_PUBLIC_AUTH_BASE_URLが正しいことを確認してください(開発ではhttp://localhost:3000)。- Google Cloud Console → Credentials で認可済みリダイレクト URI に次を追加:
http://localhost:3000/api/auth/callback/google(開発)https://あなたのドメイン.com/api/auth/callback/google(本番)
/[locale]/loginのログイン画面に「Google で続行」ボタンが表示され、OAuth フローが開始されます。