ハンズオン
認証と管理者ロール
読み取り専用/読み取り+操作の管理者ロールを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 フローが開始されます。