Guide/guides

認証アプリを作る

このガイドでは、ユーザー登録・ログイン・保護されたルートを備えたアプリケーションを構築します。空のディレクトリから認証フロー完成まで、10分以内で完了できます。

認証アプリを作る

このガイドでは、ユーザー登録・ログイン・保護されたルートを備えたアプリケーションを構築します。空のディレクトリから認証フロー完成まで、10分以内で完了できます。

Note

これはタスク指向のガイドです。セッション、ガード、ユーザープロバイダーの詳細は認証ガイドを参照してください。

前提条件

  • Bun 1.1 以降
  • Docker Desktop (Compose v2) — Postgres 用

1. プロジェクトを作成する

bunx create-guren-app my-auth-app --mode ssr
cd my-auth-app
bun install

2. 認証機能を追加する

add auth ジェネレーターを使うと、コントローラー、Inertia ページ、ユーザーモデル、マイグレーション、セッションミドルウェアが一括で生成されます:

bunx guren add auth

生成されるもの:

  • app/Http/Controllers/Auth/LoginController.tsRegisterController.ts
  • パスワードとリメンバートークンのカラムを持つ app/Models/User.ts
  • resources/js/pages/Auth/ 配下の Inertia ページ
  • アプリケーションプロバイダーに登録済みの AuthProvider
  • 開発環境向けのデフォルト設定が適用されたセッションミドルウェア
  • routes/web.ts に接続された認証ルート

3. データベースを起動する

docker compose up -d

マイグレーションを実行して users テーブルを作成します:

bunx guren db:migrate

4. 型マニフェストを生成する

bun run codegen

ルートとページの型付きマニフェストが生成され、コントローラーとフロントエンドコンポーネントの型安全性が確保されます。

5. 開発サーバーを起動する

bun run dev

http://localhost:3333/register でアカウントを作成し、http://localhost:3333/login でログインできます。

6. 主要なコードを理解する

LoginController

生成されるコントローラーは Zod でバリデーションを行い、認証ガードに処理を委譲します:

import { Controller } from '@guren/core'
import { z } from 'zod'
import { pages } from '@/.guren/pages.gen'

const LoginSchema = z.object({
  email: z.email(),
  password: z.string().min(1),
  remember: z.boolean().optional(),
})

export class LoginController extends Controller {
  async show() {
    return this.inertia(pages.auth.Login)
  }

  async login() {
    const { email, password, remember } = await this.validateBody(LoginSchema)
    const ok = await this.auth.attempt({ email, password }, remember)

    if (!ok) {
      return this.back().withErrors({ email: '認証情報が正しくありません。' })
    }

    return this.redirect('/dashboard')
  }

  async logout() {
    await this.auth.logout()
    return this.redirect('/login')
  }
}

認証ミドルウェア

ジェネレーターが登録する auth エイリアスを使って、ルートグループを保護します:

import { Router } from '@guren/core'

export function registerWebRoutes(router: Router): void {
  // 公開ルート
  router.get('/login', [LoginController, 'show']).name('login.show')
  router.post('/login', [LoginController, 'login']).name('login')
  router.post('/logout', [LoginController, 'logout']).name('logout')

  // 保護されたルート
  router.middleware('auth').group((auth) => {
    auth.get('/dashboard', [DashboardController, 'index']).name('dashboard')
  })
}

保護されたページ

保護されたコントローラー内では this.auth で現在のユーザーにアクセスできます:

export class DashboardController extends Controller {
  async index() {
    const user = await this.auth.userOrFail()
    return this.inertia(pages.dashboard.Index, { user })
  }
}

7. フローを検証する

  1. /register にアクセスしてユーザーを作成する
  2. /login にアクセスして作成した認証情報でログインする
  3. /dashboard に遷移し、ユーザー名が表示されることを確認する
  4. シークレットウィンドウで /dashboard にアクセスし、/login にリダイレクトされることを確認する
  5. ログアウトして、ログインページに戻ることを確認する

次のステップ

  • メール認証 — 保護されたルートへのアクセス前にメールアドレスの確認を要求する
  • パスワードリセット — ユーザーがアカウントを復旧できるようにする
  • 認可 — ロールベースのアクセス制御を追加する
  • API トークン — プログラムからのアクセス用トークンを発行する