【覚書】Laravel9+ laravel/breezeでのマルチログイン機能の実装

## 概要
今回は、Laravel Breezeを使ったシンプルな認証機能に、管理者（admin）の認証を追加してマルチログイン（Adminユーザー）を実装しました。
流れが多いため、どのファイルにどんな役割があるのか、覚書として記します。
対象は、すでにBreezeによるUser認証が設定済みのLaravelアプリケーションです。

## 手順
1. Adminモデルとマイグレーションの作成
1. ルートの設定
1. ルートサービスプロバイダの設定
1. 認証ガードの設定
1. 認証ミドルウェアの設定
1. リクエストクラスの修正
1. コントローラとビューの作成

## 1. Adminモデルとマイグレーションの作成
まず、Adminモデルとマイグレーションファイルを作成します。

```php artisan make:model Admin -m```
```app/Models/Admin.php``` で、Adminモデルが認証可能になるよう、```Authenticatable```を継承します。

```
<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Admin extends Authenticatable
{
    use HasFactory;
    ...
}
```
マイグレーションファイル（database/migrations/xxxx_xx_xx_xxxxxx_create_admins_table.php）もUserと同様の構成にします。
```
Schema::create('admins', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});
```

## 2. ルートの設定
Admin用のルートを ```routes/admin.php``` に記述します。ここでは、各種認証ルートと、/dashboardを設定します。

```
use App\Http\Controllers\Admin\Auth\AuthenticatedSessionController;
use Illuminate\Support\Facades\Route;

Route::get('/dashboard', function () {
    return view('admin.dashboard');
})->middleware(['auth:admin'])->name('dashboard');

Route::middleware('guest:admin')->group(function () {
    // Admin認証に必要なルートをここに追加
});
```

## 3. ルートサービスプロバイダの設定

ルートの設定とログイン後のリダイレクト先を指定するため、```app/Providers/RouteServiceProvider.php``` を修正します。

```
class RouteServiceProvider extends ServiceProvider
{
    public const HOME = '/';
    public const ADMIN_HOME = '/admin/dashboard';

    public function boot()
    {
        $this->routes(function () {
            // Admin用ルート
            Route::prefix('admin')
                ->as('admin.')
                ->middleware('web')
                ->group(base_path('routes/admin.php'));

            // User用ルート
            Route::prefix('/')
                ->as('user.')
                ->middleware('web')
                ->group(base_path('routes/web.php'));
        });
    }
}
```
### 各設定項目の解説
**prefix:**
prefixはURLの前に追加する文字列を指定します。
例えばadminをプレフィックスとして設定すると、URLは/admin/dashboardのように構成されます。
これにより、複数のルートグループ（例: 管理者用とユーザー用）を明確に区別できます。

**as:**
asはルートに別名（ルート名のプレフィックス）を付けるための設定です。
上記では、管理者用ルートにはadmin.、ユーザー用ルートにはuser.が設定されています。
例えば、管理者用のダッシュボードルートをroute('admin.dashboard')と記述でき、ルートの役割を明確に示すことができます。

**middleware:**
middlewareはルートに適用するミドルウェアを指定します。
webミドルウェアを使用することで、セッション管理やCSRF保護などの機能が適用され、ユーザー認証などに必要な機能が利用できます。
apiミドルウェアはAPI専用の機能（例: ステートレス認証やJSONレスポンス）が適用されます。

**namespace:**
namespaceはコントローラーの名前空間を指定します。
これにより、ルートで指定するコントローラーのパスを省略でき、よりシンプルなコードにできます。
ここでは、$this->namespaceを利用して設定された名前空間を使用しています。

**group:**
groupはルートをグループ化するためのメソッドです。グループ化することで、特定の設定（prefixやmiddlewareなど）を一括して適用でき、複数のルートを管理しやすくします。
ここでは、base_path('routes/admin.php')やbase_path('routes/web.php')のルートファイルがグループ化されて読み込まれます。



## 4. 認証ガードとプロバイダの設定
ガードとプロバイダを設定し、UserとAdminで別の認証ができるようにします。設定ファイル ```config/auth.php``` に追加します。

```
'guards' => [
    'users' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    'admin' => [
        'driver' => 'session',
        'provider' => 'admin',
    ],
],
'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
    'admin' => [
        'driver' => 'eloquent',
        'model' => App\Models\Admin::class,
    ],
],
```

## 5. ミドルウェアの設定
ミドルウェアを追加し、未認証時のリダイレクト先を設定します。

**```Authenticate.php```**
ユーザーごとにリダイレクト先を分けます。

```
protected function redirectTo($request)
{
    if (! $request->expectsJson()) {
        return Route::is('admin.*') ? route('admin.login') : route('user.login');
    }
}
```
**```RedirectIfAuthenticated.php```**
ログイン済みの場合のリダイレクト処理を追加します。

```
public function handle(Request $request, Closure $next, ...$guards)
{
    if (Auth::guard('admin')->check() && $request->routeIs('admin.*')) {
        return redirect(RouteServiceProvider::ADMIN_HOME);
    }

    if (Auth::guard('users')->check() && $request->routeIs('user.*')) {
        return redirect(RouteServiceProvider::HOME);
    }

    return $next($request);
}
```

## 6. リクエストクラスの修正
```app/Http/Requests/Auth/LoginRequest.php``` にて、ガードを適切に切り替えるよう修正します。

```
public function authenticate()
{
    $this->ensureIsNotRateLimited();

    $guard = $this->routeIs('admin.*') ? 'admin' : 'users';

    if (! Auth::guard($guard)->attempt($this->only('email', 'password'), $this->boolean('remember'))) {
        RateLimiter::hit($this->throttleKey());
        throw ValidationException::withMessages([
            'email' => trans('auth.failed'),
        ]);
    }

    RateLimiter::clear($this->throttleKey());
}
```
## 7. コントローラとビューの作成
```App/Http/Controllers/Admin``` フォルダに管理者用の認証コントローラを配置します。
AuthディレクトリにUser用の認証コントローラをコピーし、Admin用に修正します。

- コントローラ内でview('auth.login')をview('admin.auth.login')に、route('dashboard')をroute('admin.dashboard')に変更します。
- 各ビューも resources/views/admin/auth フォルダに作成し、User用のビューを参考に必要な箇所を変更します。


----

以上で、Laravel Breezeを使用したUserとAdminのマルチログイン機能の実装が完了です。

### 参考
https://qiita.com/tomoeine/items/40a966bf3801633cf90f
https://qiita.com/nomuraxis/items/0791dfd3eea9c5ca4085
https://readouble.com/laravel/9.x/ja/authentication.html