E040 管理者用画面とユーザー用画面の認証を分ける

前回の記事で紹介したBreezeで導入される認証機能はユーザー側だけとなります。今回はユーザー機能と管理機能を別で作成するため、Breezeで導入された認証機能をコピーして管理画面用の認証機能の作成方法を紹介します。

管理ユーザー用のモデル、テーブルを追加する

①管理ユーザー用のモデル、テーブルを追加する。

$sail php artisan make:model Admin --migration

作成されたAdmin.phpファイルにUser.phpの中身をコピーして貼り付けます。クラス名はAdminへ変更が必要です。

②作成したマイグレーションファイルをDBに適応する。

マイグレーションファイルも同様にusersテーブル作成用のマイグレーションファイルの列情報をコピーして同じテーブル構造にします。

※下記、L16~L20を参照

database/migrations/yyyy_mm_dd_xxxxxx_create_admins_table.php
 public function up(): void
     {
         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();
         });
     }

$sail artisan migrate

Guardの設定

①config/auth.phpファイルに管理者用のGuard設定を追加する。

※下記、L43~L46、L56~L59、L72~L73、L77~L81を参照

config/auth.php
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
+        'admin' => [
+            'driver' => 'session',
+            'provider' => 'admins',
+        ],
],

//中略

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
+        'admins' => [
+            'driver' => 'eloquent',
+            'model' => App\Models\Admin::class,
+        ],

    // 'users' => [
    //     'driver' => 'database',
    //     'table' => 'users',
    // ],
],

//中略

'passwords' => [
    'users' => [
        'provider' => 'users',
-       'table' => 'password_reset_tokens',
+       'table' => 'password_resets',
        'expire' => 60,
        'throttle' => 60,
    ],
+   'admins' => [
+        'provider' => 'admins',
+        'table' => 'password_resets',
+        'expire' => 60,
+        'throttle' => 60,
    ],
],

ルーティングの設定

①追加する管理者用認証のルーティングを追加するためにroutes/auth.phpファイルをコピーして/routes/admin.phpファイルとして保存する。

②追加でroutes/web.php のユーザー用ダッシュボードの設定もroutes/admin.phpにコピーする。

※下記、L59~L62を参照

routes/admin.php
Route::middleware('auth')->group(function () {
    Route::get('verify-email', EmailVerificationPromptController::class)
                ->name('verification.notice');

    Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
                ->middleware(['signed', 'throttle:6,1'])
                ->name('verification.verify');

    Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
                ->middleware('throttle:6,1')
                ->name('verification.send');

    Route::get('confirm-password', [ConfirmablePasswordController::class, 'show'])
                ->name('password.confirm');

    Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']);

    Route::put('password', [PasswordController::class, 'update'])->name('password.update');

    Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])
                ->name('logout');
+
+   Route::get('/dashboard', function () {
+               return view('dashboard');
+   })->middleware(['auth', 'verified'])->name('dashboard');
});

③admin.phpのmiddleware設定 ‘guest’と’auth’に管理者用Guardのadminを追加する。

※下記、L14~15、L19~L20を参照

routes/admin.php
- Route::middleware('guest')->group(function () {
+ Route::middleware('guest:admin')->group(function () {
//中略
}

- Route::middleware('auth')->group(function () {
+ Route::middleware('auth:admin')->group(function () {
//中略
}

④admin.phpの先頭でuse しているコントローラーファイルへのパスを変更する。

App\Http\Controllers\Auth\ → App\Http\Controllers\Admin\Auth\

※下記、L3-L11を参照

routes/admin.php
+ use App\Http\Controllers\Admin\Auth\AuthenticatedSessionController;
+ use App\Http\Controllers\Admin\Auth\ConfirmablePasswordController;
+ use App\Http\Controllers\Admin\Auth\EmailVerificationNotificationController;
+ use App\Http\Controllers\Admin\Auth\EmailVerificationPromptController;
+ use App\Http\Controllers\Admin\Auth\NewPasswordController;
+ use App\Http\Controllers\Admin\Auth\PasswordController;
+ use App\Http\Controllers\Admin\Auth\PasswordResetLinkController;
+ use App\Http\Controllers\Admin\Auth\RegisteredUserController;
+ use App\Http\Controllers\Admin\Auth\VerifyEmailController;

⑤管理画面 ルーティングの追加

※下記、L31~L33を参照

routes/web.php
Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
    Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
    Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});

+ Route::prefix('admin')->name('admin.')->group(function(){
+    require __DIR__.'/admin.php';
+ });

require __DIR__.'/auth.php';

認証用のコントローラーファイルの複製

①app/Http/Controllers/Admin フォルダを作成する。

②app/Http/Controllers/Authフォルダをフォルダごと、Adminフォルダの下にコピーする。

※Admin/Auth/xxxxxxx.phpを作成します。

③app/Http/Controllers/Admin/Auth にあるコントローラーファイルを開き、namespaceのパスを変更する。

各ファイルのL3のnamespaceにAdminを入れ下記の様に変更します。

※下記、L3~L4を参照

app/Http/Controllers/Admin/Auth/xxxxxxx.php
<?php

- namespace App\Http\Controllers\Auth;
+ namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
//以下省略

管理者ユーザ登録、ログイン画面の設定

①resouces/views/authの下に保存されているregister.blade.phpファイルを変更する。

register.blade.phpファイルにはユーザ登録のフォームがHTMLによって記述されていますが送信先がregisterになっているのでadmin.registerに変更する必要があります。

※下記、L2~L3を参照

resources/views/auth/register.blade.php
  <x-guest-layout>
-   <form method="POST" action="{{ route('register') }}">
+   <form method="POST" action="{{ route('admin.register') }}">
    @csrf

②admin/auth/login.blade.phpファイルのPOSTリクエストの送信先とリンクの設定を変更する。

※下記、 L3~L5を参照

resources/views/auth/login.blade.php
  <x-auth-session-status class="mb-4" :status="session('status')" />
  
-   <form method="POST" action="{{ route('login') }}">
+   <form method="POST" action="{{ route('admin.login') }}">
  @csrf

※下記、L37~L38を参照

resources/views/auth/login.blade.php
  <div class="flex items-center justify-end mt-4">
      @if (Route::has('admin.password.request'))
-                      <a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}">
+                      <a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('admin.password.request') }}">
              {{ __('Forgot your password?') }}
          </a>
      @endif
  
      <x-button class="ml-3">
          {{ __('Log in') }}
      </x-button>
  </div>

※admin/authの下に保存されているその他のBladeファイルconfirm-password.blade.php, forgot-password.blade.php, reset-password.blade.php, verify-email.blade.phpについてもPOSTリクエストの送信先やリンクの設定を更新を行ってください。

③Admin/Auth/RegisteredUserController.phpファイルのcreateメソッドのview関数で指定するbladeファイルを変更する。

※下記、L23~L24を参照

app/Http/Controllers/Admin/Auth/RegisteredUserController.php
  public function create()
  {
-      return view('auth.register');
+      return view('admin.auth.register');
  }

④Auth/AuthenticatedSessionController.phpファイルでもcreateメソッドを更新する。

※下記、L20-L21を参照

app/Http/Controllers/Admin/Auth/AuthenticatedSessionController.php
  public function create()
  {
-      return view('auth.login');
+      return view('admin.auth.login');
  }

※その他のConfirmablePasswordController.php, EmailVerificationPromptController.php, NewPasswordController.php, PasswordResetLinkController.phpファイルでもview関数の値を更新します。

管理者ユーザの登録

①Admin/Auth/RegisteredUserController.phpファイルのstoreメソッドを更新する。

※下記、L7、L18~L32を参照

app/Http/Controllers/Admin/Auth/RegisteredUserController.php
    use App\Http\Controllers\Controller;
    use App\Models\User;
+   use App\Models\Admin;
    use App\Providers\RouteServiceProvider;
    use Illuminate\Auth\Events\Registered;
    use Illuminate\Http\RedirectResponse;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Validation\Rules;
    use Illuminate\View\View;
    //略
    
-     public function store(Request $request): RedirectResponse
-     {
-         $request->validate([
-             'name' => ['required', 'string', 'max:255'],
-             'email' => ['required', 'string', 'email', 'max:255', 'unique:'.User::class],
-             'password' => ['required', 'confirmed', Rules\Password::defaults()],
-         ]);

+     public function store(Request $request)
+     {
+          $request->validate([
+              'name' => 'required|string|max:255',
+              'email' => 'required|string|email|max:255|unique:admins',
+              'password' => ['required', 'confirmed', Rules\Password::defaults()],
+          ]);
  
  //略

②データベースをリフレッシュする。

$php artisan migrate:refresh

リダイレクトの確認

①RouteServiceProvider.phpファイルにADMIN_HOMEを追加する。

※下記、L20~21を参照

app/Providers/RouteServiceProvider.php
- public const HOME = '/dashboard';
+ public const ADMIN_HOME = '/admin/dashboard';

②RegisteredUserController.phpのリダイレクト先をHOMEからADMIN_HOMEに変更する。

※下記、L1~L2を参照

app/Http/Controllers/Admin/Auth/RegisteredUserController.php
- return redirect(RouteServiceProvider::HOME);
+ return redirect(RouteServiceProvider::ADMIN_HOME);

ログイン処理

①LoginRequeset.phpを修正する。

ログイン後のリダイレクト先の場所をHOMEからADMIN_HOMEに変更しています。

※下記、L32~L33を参照

app/Http/Controllers/Admin/Auth/AuthenticatedSessionController.php
  public function store(LoginRequest $request): RedirectResponse
  {
      $request->authenticate();
  
      $request->session()->regenerate();
  
-     return redirect()->intended(RouteServiceProvider::HOME);
+     return redirect()->intended(RouteServiceProvider::ADMIN_HOME);
  }

webを利用した場合はusersテーブルでemailとパスワードをチェックするためadminsテーブルに登録したユーザでは認証に失敗します。

※下記、L40~L53を参照

app/Http/Requests/Auth/LoginRequest.php
public function authenticate()
{
    $this->ensureIsNotRateLimited();

    if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
        RateLimiter::hit($this->throttleKey());

        throw ValidationException::withMessages([
            'email' => __('auth.failed'),
        ]);
    }

    RateLimiter::clear($this->throttleKey());
}

ログアウト処理

①AuthenticatedSessionController.phpのdestroyメソッドを修正する。

※下記、L40~L41、L47~L48を参照

app/Http/Controllers/Admin/Auth/AuthenticatedSessionController.php
  public function destroy(Request $request)
  {
-     Auth::guard('web')->logout();
+     Auth::guard('admin')->logout();
  
      $request->session()->invalidate();
  
      $request->session()->regenerateToken();
  
-     return redirect('/');
+     return redirect('/admin/login');
  }

確認事項

・ユーザー側 /register からユーザー登録を行ない、usersテーブルにデータが登録されること、/loginからログインできるかを確認する。

・管理側 /admin/register から 管理者登録を行ない、adminsテーブルにデータが登録されること、/admin/login からログインできるかを確認する。

・ユーザー側のユーザーで管理側にログインできないこと、また、その逆も問題ないかを確認する。

---