Laravel8のバージョンで公開済みのLaravel Breezeのマルチ認証についてLaravel9でも同様に設定ができるのかを確認した文書です。

公開済みの文書ではLaravel Breezeのデフォルトの場合とInertia+Vueを利用した2つのパターンについて説明を行っていますが今回はInertia+Reactを利用しています。基本的な設定方法はLaravel8とLaravel9で同じなのでデフォルトまたはInertia + Vueの場合は上記の文書を参考にしてください。

本文書を読み進めるだけであればReactの知識は必要ありません。

Laravelプロジェクトの作成

Laravelの環境を構築するためには事前にPHPのcomposerとJavaScriptのnodeのインストールを完了しておく必要があります。

Laravelプロジェクトの作成はcomposerまたはlaravel newコマンドを利用して行います。本文書ではlaravel_breeze_multi_auth_reactというプロジェクト名をつけていますが任意の名前をつけてください。


 % laravel new laravel_breeze_multi_auth_react

composerコマンドでもプロジェクトの作成を行うことができます。


$ composer create-project --prefer-dist laravel/laravel laravel_breeze_multi_auth_react 

作成したプロジェクトに移動してphp artisanコマンドでLaravelのバージョンを確認します。本文書では9.6.0バージョンで動作確認を行っています。


 % php artisan -V
Laravel Framework 9.6.0

Laravel Breezeを利用するためにはcomposerコマンドを利用してパッケージのインストールを行う必要があります。


 % composer require laravel/breeze --dev

パッケージのインストール後にbreezeのインストールを行います。インストール時にデフォルト(Alpine.js)、Inertia.js + Vue.js, Inertia.js + Reactのどれを利用するのかオプションで指定することができます。Reactを利用する場合はreactを指定します。


 % php artisan breeze:install react

php artisan breeze:installを実行すると認証に関連するルーティングの追加、ユーザ登録、ログイン処理が記述されたコントローラーファイル、ユーザ登録、ログイン画面に関するファイルが作成されます。

breezeのインストールが完了したらnpm install && npm run devコマンドを実行してJavaScriptのパッケージとビルドを行います。


 % npm install && npm run dev

ビルドが完了後にphp artisan serveコマンドでLaravelの開発サーバの起動を行います。Breezeのインストールが完了しているので右上にはLogin inとRegisterのリンクが表示されます。各リンクをクリックするとログイン画面とユーザ登録画面が表示されます。


 % php artisan serve
Laravel9の初期画面
Laravel9の初期画面

データベースの設定

Laravelプロジェクトの作成とBreezeのインストールが完了するとユーザの登録画面が表示されますがデータベースがないためユーザの登録を行うことができません。ユーザの登録が行えるようにデータベースの作成を行います。簡易的に利用することができるSQLiteデータベースを利用します。SQLiteではデータベースにファイルを利用するためtouchコマンドでdatabaseフォルダの下にdatabase.sqliteファイルを作成します。


 % touch database/database.sqlite

LaravelからSQLiteデータベースに接続するために環境変数を含む.envファイルの更新します。.envファイルには先頭にDB_のついている環境変数が複数ありますが、DB_CONNECTIONを残してDB_から始まる変数を削除します。DB_CONNECTIONにはデフォルトでmysqlが設定されていますがsqliteに変更します。


DB_CONNECTION=sqlite

.envファイルを更新後、データベースにテーブルを作成するためにphp artisan migrateコマンドを実行します。


 % php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (3.15ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (1.92ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (1.91ms)
Migrating: 2019_12_14_000001_create_personal_access_tokens_table
Migrated:  2019_12_14_000001_create_personal_access_tokens_table (2.49ms)

マルチ認証の設定

モデルファイルの作成

マルチ認証を利用する場合は認証によってユーザ情報を保存するテーブルを分けます。デフォルトの認証ではusersテーブルを利用します。新たに認証に利用するテーブルを作成しますがテーブル名についてはマルチ認証を利用するアプリケーションによって変更することができます。本文書ではadminsテーブルを利用するためモデルファイルにはAdmin.phpを利用します。モデルファイルの作成にはphp artisan make:modelコマンドを利用し-mオプションをつけます。-mオプションでマイグレーションファイルも同時に作成されます。


 % php artisan make:model Admin -m
Model created successfully.
Created Migration: 2022_04_05_040501_create_admins_table

作成されたAdmin.phpファイルはapp¥MoldesフォルダにあるUser.phpの中身をコピーして貼り付けます。コピー後にクラス名はAdminにして保存してください。


namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class Admin extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

作成されたマイグレーションファイルもusersテーブル作成用のマイグレーションファイルの列情報をコピーして利用します。


public function up()
{
    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();
    });
}

php artisan make:migrateコマンドを実行してadminsテーブルを作成します。


% php artisan migrate
Migrating: 2022_04_05_040501_create_admins_table
Migrated:  2022_04_05_040501_create_admins_table (7.82ms)

Guardの設定

Laravelは認証の仕組みとしてGuardを利用します。名前の通りLaravelにアクセスするリクエストに対してガードする(守る)役目を持っています。 デフォルトではブラウザからのアクセス用のwebとAPI用のapiが設定されています。ルーティングに対してweb guardを設定している場合はログイン画面からのユーザの認証が行われていないとweb guardを設定した場所にアクセスすることができません。

Guardは追加を行うことができるので追加認証機能のために新たにadmin guardの追加を行います。設定はconfig/auth.phpファイルで行います。Guardがどのような処理を行われているかがわからなくても追加したadminの内容を見るとモデルApp\Models\Admin 、パスワード、adminsテーブルに関連していることがわかります。


//中略

'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_resets',
        'expire' => 60,
        'throttle' => 60,
    ],
    'admins' => [
        'provider' => 'admins',
        'table' => 'password_resets',
        'expire' => 60,
        'throttle' => 60,
    ],
],

ルーティングの設定

breeze:installを実行するとルーティングのweb.phpファイルにはログイン後に表示されるダッシュボードに関するルーティングと認証に関するルーティングが追加されます。認証に関するルーティングについてはauth.phpファイルに記述されています。


Route::get('/dashboard', function () {
    return Inertia::render('Dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');

require __DIR__.'/auth.php';

auth.phpファイルによってどのようなルーティングが追加されているかはphp artisan route:listコマンドを実行することがで確認することができます。/login, /registerなど認証に関するルーティングが追加されていることを確認してください。

ルーティングの確認
ルーティングの確認

追加するadmin認証についてのルーティングを追加するためにroutes/auth.phpファイルを複製して/routes/admin.phpファイルを作成します。

作成したadmin.phpでは名前空間の設定変更とmiddlewareにパラメータadminを追加します。

この後認証に関連するコントローラーファイルをapp\HTTP\Controllersの下のAdminの下に保存するのでインポートするクラスのパスを下記のように変更します。Authの前にAdminを追加します。


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\PasswordResetLinkController;
use App\Http\Controllers\Admin\Auth\RegisteredUserController;
use App\Http\Controllers\Admin\Auth\VerifyEmailController;
use Illuminate\Support\Facades\Route;

Route::middleware('guest:admin')->group(function () {
    //略
});

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

作成したadmin.phpファイルをauth.phpファイルと同じ方法でweb.phpファイルに追加します。


require __DIR__.'/auth.php';

require __DIR__.'/admin.php';

php artisan route:listコマンドを実行しても追加したルーティング(admin.php)に関するコントローラーが存在しないためエラーになります。


 % php artisan route:list

   Illuminate\Contracts\Container\BindingResolutionException 

  Target class [App\Http\Controllers\Admin\Auth\RegisteredUserController] does not exist.

コントローラーの作成

追加のadmin認証に関連するコントローラーファイルを保存するためにapp¥HTTP¥ControllersにAdminフォルダを作成します。Adminフォルダの下にbreeze:install実行後に作成されたapp¥HTTP¥Controllers¥Authフォルダをそのままコピーします。


 % mkdir Admin
 % cp -r Auth Admin

Admin¥Authフォルダの下には8つのコントロールファイルがありますがすべてのファイルを開いて名前空間の変更を行います。Authの名前の前にAdminを挿入してください。変更の目的はファイルをAdminフォルダにコピーして名前空間のパスが変わったためです。


namespace App\Http\Controllers\Admin\Auth;

dmin¥Authフォルダの下にある8つのファイルの名前空間を変更すると先ほど失敗したphp artisan route:listコマンドを実行することができます。


 % php artisan route:list

しかし、ルーティングは追加されておらずファイル名の先頭にAdminが追加されているだけです。理由はroutes/auth.phpとadmin.phpファイルのルーティング先の設定が同じためです。auth.phpとadmin.phpでルーティング先の/registerが2回登録され後から追加したadmin.phpファイルのルーティングによってauth.phpファイルのルーティングが上書きされています。上書きされるのは/registerだけでなく/loginなどauth.phpに記述されているすべてのルーティングです。

ルーティングの確認
ルーティングの確認

ルーティングの重複を避けるためデフォルト認証のルーティングの/registerを追加するadmin認証では/admin/registerとします。そのためにadmin.phpファイルのルーティングにprefixで一括で/adminを追加します。URLだけではなくnameも区別するためにname列にnameメソッドによりはadmin.を先頭につけます。


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

設定後にphp artisan route:listを実行するとURI列にadmin/、Name列にadmin.が追加されたルーティングが表示されます。

auth.phpとadmin.phpのルーティングが表示
auth.phpとadmin.phpのルーティングが表示

ここまでの設定が完了するとブラウザで/admin/register, /admin/loginにアクセスするとユーザ登録画面とログイン画面が表示され/admin/register画面からユーザを登録することができます。しかし、登録したユーザが保存されるテーブルはadminsではなくusersなのでマルチ認証の設定は完了していません。

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

追加したadmin認証でユーザを正しく登録するためにはフロントエンド画面の設定を変更する必要があります。

Inertia+Reactの場合

admin.phpで追加したルーティングを確認するとユーザ登録画面の/admin/registerにアクセスするとapp¥Http¥Controller¥Admin¥Auth¥RegisteredUserController.phpファイルのcreateメソッドが実行されます。


public function create()
{
    return Inertia::render('Auth/Register');
}

render関数の中にあるAuth/Registerは¥resources¥js¥Pagesの下に保存されているAuth¥Register.jsファイルです。Register.jsファイルを開いてsubmit関数を確認してください。postリクエストの送信先がregisterになっていることがわかります。


const submit = (e) => {
    e.preventDefault();

    post(route('register'));
};

これはデフォルト認証が利用するルーティングなのでregisterではなくadmin.registerに変更する必要があります。Auth¥Register.jsファイルはデフォルトの認証で利用するため更新することはできません。そのためPagesフォルダに新たにAdminフォルダを作成しAuthフォルダをAdminフォルダの下にコピーします。


% mkdir Admin
% cp -r Auth Admin 
// resources¥js¥Pagesフォルダで実行

Admin¥Authの下にコピーしたRegister.jsファイルを開いてsubmitメソッドを変更します。


const submit = (e) => {
    e.preventDefault();

    post(route('admin.register'));
};

ログインページへのリンクが設定されているroute関数の引数に設定されている値も変更を行います。loginからadmin.loginに変更しています。loginからadmin.logingへの変更はルーティングのname列の値に対応し/registerから/admin/registerに変更したことを意味します。


<div className="flex items-center justify-end mt-4">
    <Link
        href={route("admin.login")}
        className="underline text-sm text-gray-600 hover:text-gray-900"
    >
        Already registered?
    </Link>

    <Button className="ml-4" processing={processing}>
        Register
    </Button>
</div>

Admin¥Auth¥Login.jsファイルのPOSTリエクストの送信先とroute関数の引数を変更します。


const submit = (e) => {
    e.preventDefault();

    post(route('admin.login'));
};

<div className="flex items-center justify-end mt-4">
    {canResetPassword && (
        <Link
            href={route('admin.password.request')}
            className="underline text-sm text-gray-600 hover:text-gray-900"
        >
            Forgot your password?
        </Link> 
    )}

    <Button className="ml-4" processing={processing}>
        Log in
    </Button>
</div>

その他のConfirmPassword.js, ForgotPassword.js, ResetPasswod.js, VerifyEmail.jsファイルも同様にPOSTリクエスト先とroute関数の設定がある場合は引数の値を変更してください。

jsファイルを更新したら更新内容を反映させるためにビルドが必要になります。npm run watchコマンドを実行するとjsファイルの更新を検知しビルドを自動で行います。


% npm run watch

jsファイルの変更が完了したら再度RegisteredUserController.phpファイルを確認します。createメソッドのrenderメソッドはAuth/Registerになっていますが先ほどAdmin/Auth/Registerを作成したので変更を行います。


public function create()
{
    return Inertia::render('Admin/Auth/Register');
}

/admin/registerにブラウザからアクセスするとAdmin/Auth/Registerファイルの内容が表示されることになります。 Admin¥Authフォルダに保存されているコントロラーファイルすべてを確認してInertia::render関数の値を変更します。

ログイン処理に関係するAuthenticatedSessionController.phpでもcreateメソッドのrender関数の値をAuth/LoginからAdmin/Auth/Loginに変更します。


public function create()
{
    return Inertia::render('Admin/Auth/Login', [
        'canResetPassword' => Route::has('password.request'),
        'status' => session('status'),
    ]);
}

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


public function show()
{
    return Inertia::render('Admin/Auth/ConfirmPassword');
}

public function __invoke(Request $request)
{
    return $request->user()->hasVerifiedEmail()
                ? redirect()->intended(RouteServiceProvider::HOME)
                : Inertia::render('Admin/Auth/VerifyEmail', ['status' => session('status')]);
}

public function create(Request $request)
{
    return Inertia::render('Admin/Auth/ResetPassword', [
        'email' => $request->email,
        'token' => $request->route('token'),
    ]);
}

public function create()
{
    return Inertia::render('Admin/Auth/ForgotPassword', [
        'status' => session('status'),
    ]);
}

ユーザの登録

ユーザ登録画面の表示では、Admin¥RegisteredUserController.phpファイルのcreateメソッドに注目していましたがユーザの登録を行う際はstoreメソッドに注目します。

storeメソッドはUserモデルが利用されているためUserからAdminモデルへ変更を行います。またemailのバリデーションでusersテーブルにunique設定が行われているのでusersからadminsに変更します。


//略
use App\Models\Admin;
//略
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()],
        ]);

        $user = Admin::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);
//略

ファイルの更新が完了したらブラウザで/admin/registerにアクセスします。ファイルが更新されているか確認するために”Already registgered”にカーソルを当ててリンク先が/admin/loginになっているか確認してください。もし/loginのままの場合は正しいファイルが更新されていないかReactの場合はJavaScriptファイルのキャッシュがクリアされていない可能性があるのでブラウザのキャッシュのクリアを行ってください。

リンクの確認
リンクの確認

adminsテーブルにユーザが登録できるかどうか確認するために一度データベースをリフレッシュします。


% php artisan migrate:refresh

ユーザ登録画面からユーザの登録を行いadminsテーブルにユーザ情報が追加されるか確認を行ってください。本文書ではデータベースのGUIの管理ソフトウェアであるTablePlusを利用していています。

adminsテーブルへのユーザ登録の確認
adminsテーブルへのユーザ登録の確認

/admin/registerのユーザ登録画面からユーザを登録するとadminsテーブルへのユーザ登録が完了してもここまでの設定では登録後にリダイレクト(/loginへ)が行われブラウザ上にはログイン画面が表示されダッシュボードは表示されません。

ダッシュボードへのリダイレクト

RegisteredUserController.phpでのユーザ登録後の処理を確認します。redirect関数の引数にRouteServiceProvider.phpで設定されているHOMEが指定されています。これはユーザ登録後にHOMEに指定されているURLにリダイレクトされることになります。


return redirect(RouteServiceProvider::HOME);

RegisteredUserController.phpを開いてHOMEの値を確認します。HOMEには/dashboardが設定されています。


class RouteServiceProvider extends ServiceProvider
{
    public const HOME = '/dashboard'
//略

HOMEには/dashboardが設定さているためユーザの作成が完了すると/dashboardにリダイレクトされます。/dashboardはデフォルトのユーザ用のダッシュボードなので新たにadmin認証用のダッシュボードを設定する必要があります。

/dashboardにリダイレクトされるとデフォルト認証のチェックが行われusersテーブルにユーザは登録されていないため認証に失敗して/loginにリダイレクトされログイン画面が表示されます。
fukidashi

RouteServiceProvider.phpファイルにADMIN_HOMEを追加します。ADMIN_HOMEには/admin/dashboardを設定します。


public const ADMIN_HOME = '/admin/dashboard';

ADMIN_HOMEを追加したらRegisteredUserController.phpのリダイレクト先をHOMEからADMIN_HOMEに変更します。これでユーザの登録が完了したらADMIN_HOMEの/admin/dashboardにリダレクトすることになります。


return redirect(RouteServiceProvider::ADMIN_HOME);

ダッシューボードページの作成

web.phpファイルには/admin/dashboardのルーティングが存在しないので/dashboardを参考に新たに追加します。render関数で指定されているDashboardファイルもadmin用にAdmin/Dashboardに変更しています。middlewareのauthにもパラメータのadminを追加しています。


Route::prefix('admin')->name('admin.')->group(function(){

    Route::get('/dashboard', function () {
        return Inertia::render('Admin/Dashboard');
    })->middleware(['auth:admin', 'verified'])->name('dashboard');

    require __DIR__.'/admin.php';
});

render関数で指定したAdmin¥Dashboardを作成します。PagesフォルダにあるDashboard.jsをPages¥Adminフォルダにコピーします。

Dashboard.jsファイルの中ではページのレイアウトとしてAuthenticatedコンポーネントを利用しています。Authenticatedコンポーネント内のリンク先はすべてデフォルト認証用のルーティングが設定されているのでresources¥js¥Layoutsフォルダ下にあるAuthenticated.jsファイルをコピーしてAdminAuthenticated.jsファイルを作成します。

作成したAdminAuthenticated.jsファイルではリンク先にadmin用のルーティングを指定するためroute関数の中に設定している値にadmin.をつけています。特にログアウトのroute関数は忘れずに変更を行ってください。


<Dropdown.Content>
    <Dropdown.Link
        href={route("admin.logout")}
        method="post"
        as="button"
    >
        Log Out
    </Dropdown.Link>
</Dropdown.Content>

<NavLink
    href={route("admin.dashboard")}
    active={route().current("admin.dashboard")}
>
    Dashboard
</NavLink>

レスポンシブ用のrouteの変更も行います。


<ResponsiveNavLink
    href={route("admin.dashboard")}
    active={route().current("admin.dashboard")}
>
    Dashboard
</ResponsiveNavLink>

<div className="mt-3 space-y-1">
    <ResponsiveNavLink
        method="post"
        href={route("admin.logout")}
        as="button"
    >
        Log Out
    </ResponsiveNavLink>
</div>

AdminAuthenticated.jsファイルの更新が完了したらPages¥Admin¥Dashboard.vueファイルでレイアウトのコンポーネントであるAuthenticatedをAdminAuthenticatedに変更します。


import React from "react";
import Authenticated from "@/Layouts/AdminAuthenticated";
import { Head } from "@inertiajs/inertia-react";

デフォルトとadmin認証用のどちらのDashboard.jsファイルが表示されているのかすぐに区別できるように”You’re logged in!”を”You’re Admin User!”に変更します。

リダイレクトの確認

ユーザ登録後のリダイレクト

追加したadmin認証のダッシュボードページが作成できたら/admin/registerからユーザの登録を行います。ユーザを登録する前にデータベースのリフレッシュを行っておきます。


% php artisan migrate:refresh

ブラウザで/admin/registerにアクセスしてユーザの登録を行います。しかし先ほどと変わらずログイン画面が表示されます。

再度ユーザ登録後の処理を確認するためRegisteredUserController.phpファイルを確認します。ユーザ作成後にlogin処理を行う部分でguardにadminを設定します。


// Auth::login($user) 変更前
Auth::guard('admin')->login($user);

再度データベースのリフレッシュを行います。


% php artisan migrate:refresh

/admin/registerからユーザを登録するとようやくAdmin用のダッシュボードが表示されます。

ダッシュボードの表示
ダッシュボードの表示

ログイン後のリダイレクト

admin認証でログインした状態で/admin/loginや/admin/registerにアクセスを行うと/login画面にリダイレクトされます。ログイン中の場合は/admin/dashboardへリダイレクトされるようにmiddewareのguestに対応するRedirectIfAuthenticated.phpファイルの設定を行います。$guardの値がadminの場合はRouteServiceProviderのADMIN_HOMEにリダイレクトする設定を行っています。


public function handle(Request $request, Closure $next, ...$guards)
{
    
    $guards = empty($guards) ? [null] : $guards;

    foreach ($guards as $guard) {
        if (Auth::guard($guard)->check()) {
            if($guard == 'admin') return redirect(RouteServiceProvider::ADMIN_HOME);
            return redirect(RouteServiceProvider::HOME);
        }
    }

    return $next($request);
}

設定後にログインした状態で/admin/registerにアクセスすろ/admin/dashboardにリダイレクトされることが確認できます。

routesフォルダのadmin.phpファイルで/regisrer, /loginなどのルーティングにmiddlewareのguestが利用されているためにmiddewareのguestに対応するRedirectIfAuthenticated.phpファイルの設定を行っています。
fukidashi

ログアウト処理

ログインしたユーザをログアウトする場合はAuthenticatedSessionController.phpファイルのdestoryメソッドが実行されます。Admin認証なのでAdmin/AuthフォルダにあるAuthenticatedSessionController.phpファイルを更新します。

デフォルトではguardのwebが設定されているのでadminに変更します。リダイレクト先が”/”に設定さているので/admin/loginに変更を行っています。リダイレクト先は任意なので好きな場所を指定してください。


public function destroy(Request $request)
{
    Auth::guard('admin')->logout();

    $request->session()->invalidate();

    $request->session()->regenerateToken();

    return redirect('/admin/login');
}

ダッシュボード画面の右側にあるユーザ名をクリックするとドロップダウンメニューが表示されLogoutがあるのでクリックします。クリックすると/admin/login画面にリダイレクトされます。

ログイン処理

ユーザの登録までの設定が完了できたので/admin/login画面からログインを行います。登録済みユーザでログインしようとしてもログインを行うことができません。

ログインの失敗
ログインの失敗

ログイン処理を行うHttp¥Controllers¥Admin¥Auth¥AuthenticatedSessionController.phpファイルのstoreメソッドを確認します。authenticateメソッド中で認証のチェックが行われているのでstore関数の引数に設定されているLoginRequeset.phpファイルの中身を確認しますがその前にログイン後のリダイレクト先の場所をHOMEからADMIN_HOMEに変更しています。


public function store(LoginRequest $request)
{
    $request->authenticate();

    $request->session()->regenerate();

    return redirect()->intended(RouteServiceProvider::ADMIN_HOME);
}

LoginRequest.phpファイルの中ではauthenticateで認証のチェック(Auth::attempt)を行っていますがデフォルトではguardを指定しないためデフォルトのwebが利用されます。webを利用した場合はusersテーブルでemailとパスワードをチェックするためadminsテーブルに登録したユーザでは認証に失敗します。


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

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

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

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

リクエストの変数$requestにはアクセスしてきたURLの情報を持っているのでここでもその情報を利用します。URLがadmin/*の場合は$guardの値をadminにし、それ以外の場合はwebにしています。


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

    $this->is('admin/*') ? $guard = 'admin' : $guard = 'web';

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

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

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

設定後、/admin/loginからユーザ登録したユーザでログインを行うとadmin用のダッシュボードが表示されます。

ログイン前のリダイレクト

ログインする前に/admin/dashboardにアクセスを行うと/loginにリダイレクトされます。アクセス制限のある/admin/以下のページにアクセスした場合はadmin認証のログイン画面である/admin/loginにリダイレクトできるように設定を行います。

web.phpファイルで追加したルーティングへアクセスの制限はmiddlewareのauthによって制御されているのでAuthenticate.phpファイルを更新します。認証が行われていない場合はredirectToメソッドが実行されます。デフォルトでは/loginにリダイレクトされるように設定されているのでadmin以下のURLからアクセスの場合はadmin.login(=/admin/login)にリダイレクトするように変更を行います。リクエストの変数$requestにはアクセスしたURLの情報を持っているのでisメソッドを利用することでadmin/*と一致するパスの場合はtrueが戻されます。*はワイルドカードとして利用できます。


protected function redirectTo($request)
{

    if (! $request->expectsJson()) {
        if($request->is('admin/*')) return route('admin.login');
        return route('login');
    }
}

Authenticate.phpを更新してログイン前に/admin/dashboardにアクセスすると/admin/loginにリダイレクトされるようになります。

まとめ

ここまでの設定で追加したadmin認証でもユーザの登録、ユーザのログイン、ログアウト処理がデフォルトの認証とは独立して動作するようになりました。パスワードリセットなどの機能を利用する場合は追加の設定が必要となります。