Laravel8から認証にJetStreamが追加されました。JetStreamをインストールしたのはいいければ以前のLaravel/uiパッケージとどこが違うのかまたどのように動作しているのか気になる人も多いかと思います。まだJetStreamを使いこなせている人も多くはないと思うので本文書ではJetStremaの認証機能に注目して説明を行いたいと思います。

JetStreamには認証画面などのScaffoldingが含まれていますが、認証のコア処理部分はFortifyというパッケージを利用しています。

JetStreamの認証機能のコアであるFortify単独を理解したいのであれば下記はおすすめです。JetStreamの力を借りず自分で認証を実装することができます。

JetStream

JetStreamをインストールし、/registerにアクセスすればユーザ登録画面、/loginにアクセスすればログイン画面が表示されるのでLaravel7までと同様に認証機能をすぐに利用することはできます。

しかしこれまで利用したきたlaravel/uiのscafolldingから変更が加えられているのでログイン画面はどのような流れで表示され、ログイン画面の更新にはどのファイルを更新すればいいのかわからない人もいるかと思います。

JetStreamはユーザの登録、ログイン機能の認証だけの機能を持つわけではありませんが、JetStreamを理解する上で最も重要な認証に注目してその流れを確認したいと思います。

ログイン画面が表示する流れ

JetStreamをインストール後に/loginにアクセスするとログイン画面が表示されます。

Laravel8ログイン画面
Laravel8ログイン画面

このログイン画面がどのような処理を通してブラウザに表示されるのか確認していきます。

ルーティングの確認

loginにアクセスするとログイン画面が表示されますがloginにアクセスした際にどのファイルのどのメソッドが実行されるのかを確認する必要があります。

php artisan route:listコマンドでルーティングを確認することができます。


 % php artisan route:list

JetStreamには様々な機能が含まれているのでデフォルトでは相当な数のルーティングが追加されているため、php artisan route:listを実行するとかなりの行が表示されるのでここではコマンドの実行結果は表示しませんがURI列にあるloginを探してください。

loginを見つけたらその行のAction列を見てください。それがloginにアクセスした際に実行されるファイルとメソッドです。

Laravel\Fortify\Http\Controllers\AuthenticatedSessionController@create  

AuthenticatedSessionControllerのcreateメソッド

AuthenticatedSessionController.phpファイルのcreateメソッドを確認します。createメソッドの中ではapp(LoginViewResponse::class)を実行しているだけです。Laravel\Fortify\Contracts\LoginViewResponse.phpファイルの中身を確認してもこのファイルはインターフェイスなので実際の処理は何も記述されていません。appで指定したLoginViewResponseの実体ファイルがわからなければcreateメソッドの処理を理解することはできないためLoginViewResponseの実体ファイルを見つける必要があります。


public function create(Request $request): LoginViewResponse
{
    return app(LoginViewResponse::class);
}

サービスプロバイダー

追加のパッケージを利用する場合パッケージインストール後にサービスプロバイダーの情報をconfigディレクトリにあるapp.phpファイルに追加を行います。

app.phpはLaravelへのアクセス時にLaravelがロードするサービスの一覧が記述されています。各サービスのロード時にどのような処理を行うのかがサービスプロバイダーファイルの中に記述されており、サービス毎で個別のサービスプロバイダーファイルを持っています。
fukidashi

app.phpファイルを確認すると認証に関連するFortifyとJetstreamのサービスプロバイダーが登録されていることが確認できます。それらのファイルはapp¥providers以下に保存されています。


'providers' => [

//略
    App\Providers\RouteServiceProvider::class,
    App\Providers\FortifyServiceProvider::class, //ここ
    App\Providers\JetstreamServiceProvider::class, //ここ

],

残念なことに上記のFortifyServiceProvider.php, JetstreamServiceProvider.phpファイルのコードを見てもLoginViewReponseクラスに関する記述はありません。

JetstreamServiceProvider.phpファイル

実はJetstreamServiceProvider.phpファイルは2つ存在し、一つはconfig/app.phpファイルに登録されているものでもう一つはvendor¥laravel¥jetstream¥srcの下にあります。

ログイン画面に関連する内容はこのファイルに記述されており、このファイルの内容を確認することでログイン画面の表示の流れを理解することができます。

vendor¥laravel¥jetstream¥src¥JetstreamServiceProvider.php

JetstreamServiceProvider.phpはサービスプロバイダーファイルなのでbootメソッドとregisterメソッドを持ちます。

bootメソッドを確認するとFortify::viewPrefix(‘auth.’)がありFortify, authという単語から認証に関係していることがわかります。

Jetstreamの認証機能にはFortifyパッケージが利用されています。
fukidashi

public function boot()
{
    $this->loadViewsFrom(__DIR__.'/../resources/views', 'jetstream');

    Fortify::viewPrefix('auth.');
//略
}

Laravel¥Fortify¥Fortify¥Fortify.phpの中身を確認するとviewPrefixメソッドの中でビューに関連する7つの処理がおこなわれていることがわかります。


public static function viewPrefix(string $prefix)
{
    static::loginView($prefix.'login');
    static::twoFactorChallengeView($prefix.'two-factor-challenge');
    static::registerView($prefix.'register');
    static::requestPasswordResetLinkView($prefix.'forgot-password');
    static::resetPasswordView($prefix.'reset-password');
    static::verifyEmailView($prefix.'verify-email');
    static::confirmPasswordView($prefix.'confirm-password');
}

ログインに関するメソッドは一番上にあるloginViewメソッドで引数に$prefixを受け取っています。$prefixは’auth.’なので引数はauth.loginになることがわかります。

loginViewメソッドを確認するとsingletonメソッドでサービスコンテナにLoginViewResponseを登録しています。


public static function loginView($view)
{
    app()->singleton(LoginViewResponse::class, function () use ($view) {
        return new SimpleViewResponse($view);
    });
}

これらの流れからAuthenticatedSessionController.phpでapp(LoginViewResponse::class)が実行されると引数に$view(=auth.login)が入ったSimpleViewResponseのインスタンスが作成されることがわかります。

SimpleViewResponse.phpファイルのtoResponseメソッドの中でviewメソッドが実行されていることがわかります。つまりbladeファイルの”auth.login”がviewメソッドを使って表示されるという流れになっています。


    public function toResponse($request)
    {
        if (! is_callable($this->view) || is_string($this->view)) {
            return view($this->view, ['request' => $request]);
        }
//略        

resource¥views¥auth¥login.blade.phpファイルがログイン画面の内容であることがわかります。/loginにアクセスするとlogin.blade.phpファイルの内容が表示され、ログイン画面を更新したい場合はlogin.blade.phpファイルを更新すればいいことがわかりました。

ログイン画面の内容について

ログイン画面がlogin.blade.phpであることがわかったのでログイン画面を更新できるようにlogin.blade.phpファイルの中身を確認していきます。

Blade Componentの登場

この文書を読んでいる方の中でもBladeのComponentを知っている人がどれくらいいるのかわかりませんが、login.blade.phpファイルの先頭の<x-guest-layout>を見てこれ何!?と驚かれた人もいるのではないでしょうか。


<x-guest-layout>
    <x-jet-authentication-card>
        <x-slot name="logo">
            <x-jet-authentication-card-logo />
        </x-slot>
//略
    </x-jet-authentication-card>
</x-guest-layout>

x-guest-layoutと表示されていますが、これはBlade Componentsのタグでこのタグに対応するクラスファイルが存在します。

x-guest-layoutについて

x-guest-layoutに対応するファイルはapp¥View¥Componentsディレクトリ以下に保存されているGuestLayout.phpに対応します。x-guest-layoutタグがGuestLayout.phpに対応するということを理解するためにはBlade Componentsの2つのルールを知っておく必要があります。

  1. Blade Componentsのタグはクラスファイル名のケバブケースで先頭にx-がつきます。コンポーネントの名前がAppLayoutなのでタグはx-app-layoutになります。
  2. Blade ComponentsファイルはApp¥View¥Componentsに保存すると自動で認識されます。

この2つのルールによりx-guest-layoutのコンポーネントファイルがapp¥View¥Components¥GuestLayout.phpに対応することがわかります。

GuestLayout.phpファイル

GuestLayout.phpファイルの中では、renderメソッドで描写するviewファイルが指定されています。


namespace App\View\Components;

use Illuminate\View\Component;

class GuestLayout extends Component
{
    /**
     * Get the view / contents that represents the component.
     *
     * @return \Illuminate\View\View
     */
    public function render()
    {
        return view('layouts.guest');
    }
}

viewメソッドの引数に指定されているファイルはviews¥layoutsディレクトリのguest.blade.phpファイルです。

guest.blade.phpファイルを開くと下部に{{ $slot }}を見つけることができます。この{{ $slot }}にlogin.blade.phpファイルの<x-guest-layout>の内側のコンテンツが挿入されることになります。


<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">

        <title>{{ config('app.name', 'Laravel') }}</title>

        <!-- Fonts -->
        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">

        <!-- Styles -->
        <link rel="stylesheet" href="{{ asset('css/app.css') }}">

        <!-- Scripts -->
        <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.7.0/dist/alpine.js" defer></script>
    </head>
    <body>
        <div class="font-sans text-gray-900 antialiased">
            {{ $slot }}
        </div>
    </body>
</html>

guest.blade.phpファイルの中身が本当に表示されている内容なのか確認するためにpタグを追加します。


<p>動作確認中</p>
<div class="font-sans text-gray-900 antialiased">
    {{ $slot }}
</div>

ブラウザで確認するとログイン画面の上部に追加した文字列が表示されることがわかります。このことから間違いなくguest.blade.phpファイルの中身がログイン画面に描写されていることがわかります。

guest.blade.phpにpタグを追加
guest.blade.phpにpタグを追加

その他のx-タグについて

x-guest-layoutは理解することができましたがその内部にあるタグx-jet-authentication-cardタグについては対応するファイルをapp¥View¥Componentsディレクトリの中に見つけることはできません。

ここで再度サービスプロバイダーファイルのJetstreamServiceProvider.phpファイルが登場します。サービスプロバイダーが出てきた場合には事前に情報が登録されることを意味します。

再度ファイルの中身を中身を確認するとbootメソッド内でコンポーネントの登録(configureComponents)が実行されていることがわかります。


public function boot()
{
    $this->loadViewsFrom(__DIR__.'/../resources/views', 'jetstream');

    Fortify::viewPrefix('auth.');

    $this->configureComponents(); //ここ
    $this->configurePublishing();
    $this->configureRoutes();
    $this->configureCommands();

    if (config('jetstream.stack') === 'inertia') {
        $this->bootInertia();
    }
}

configureComponentsメソッドの中身を確認すると一つではなく複数のコンポーネントの登録処理が行われていることがわかります。この処理の中にauthentication-cardという文字列も見つけることができます。

Componentファイルはapp¥View¥Componentsとresource¥view¥componentsディレクトリに保存すると自動で見つけてくれます。しかしそれ以外の場所に保存されている場合はBalde::componentで登録を行う必要があります。
fukidashi

このファイルでもBlade::componentを利用して登録を行い登録時に先頭にjet-付与にauthentication-cardであればjet-authentication-cardとして登録されていることがわかります。そのためBladeファイルから利用するときはx-を先頭につけて利用します。


protected function configureComponents()
{
    $this->callAfterResolving(BladeCompiler::class, function () {
        $this->registerComponent('action-message');
        $this->registerComponent('action-section');
        $this->registerComponent('application-logo');
        $this->registerComponent('application-mark');
        $this->registerComponent('authentication-card'); //ここ
//略


    protected function registerComponent(string $component)
    {
        Blade::component('jetstream::components.'.$component, 'jet-'.$component);
    }

componentのx-ファイルの保存場所

authentication-cardに対応するファイルはvendor¥laravel¥jetstream¥resource¥views¥componentsディレクトリにあるauthentication-card.blade.phpファイルです。

それらのファイルは下記のコマンドを実行することでresources¥views¥vendor¥jetstreamディレクトリに作成され更新を行うことが可能になります。画面のカスタマイズを行いたい場合はこのコマンドを実行する必要があります。


 % php artisan vendor:publish --tag=jetstream-views
Copied Directory [/vendor/laravel/jetstream/resources/views] To [/resources/views/vendor/jetstream]

authentication-card.blade.phpの確認

authentication-card.blade.phpの中身は下記の通りです。{{ $logo }}と{{ $slot}}という2つのSlotがあります。{{ $slot }}はデフォルトのslotですが、{{ $logo }}は名前付きSlotと呼ばれ、名前付きSlotの中に表示させる時はx-slotタグにname属性をつけてそのSlot名を指定する必要があります。


<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
    <div>
        {{ $logo }}
    </div>

    <div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg">
        {{ $slot }}
    </div>
</div>

x-jet-authentication-cardタグを持つlogin.blade.phpファイルでは{{ $logo}}の中に指定したコンテンツを挿入させるためx-slotを利用しています。<x-jet-authentication-card-logo />がauthentication-card.blade.phpの{{ $logo }}の部分に挿入されることになります。


<x-guest-layout>
    <x-jet-authentication-card>
        <x-slot name="logo">
            <x-jet-authentication-card-logo />
        </x-slot>
//略

<x-jet-authentication-card-logo />に対応するファイルもresources¥views¥vendor¥jetstreamディレクトリにあります。authentication-card-logo.blade.phpの中身はaタグでラップされたsvgです。このsvgがログイン画面に表示されている丸いロゴになります。変更したければこのSVGを差し替えることで実現可能です。


<a href="/">
    <svg class="w-16 h-16" viewbox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path d="M11.395 44.428C4.557 40.198 0 32.632 0 24 0 10.745 10.745 0 24 0a23.891 23.891 0 0113.997 4.502c-.2 17.907-11.097 33.245-26.602 39.926z" fill="#6875F5"/>
        <path d="M14.134 45.885A23.914 23.914 0 0024 48c13.255 0 24-10.745 24-24 0-3.516-.756-6.856-2.115-9.866-4.659 15.143-16.608 27.092-31.75 31.751z" fill="#6875F5"/>
    </svg>
</a>

BladeのComponentを利用した経験がない人にとっては最初は難しく感じたかもしれません。しかしどのタグがどのファイルに対応するかわかればシンプルなことが理解できます。

各タグのclassはすべてtailwindcssが使われているのでtailwindcssを知らない人はどのようにCSSが設定されるのか気になるかと思います。

ここまでの確認でログイン画面が表示される流れとログイン画面の中身がどのように構成されているか理解することができました。

ユーザの登録について

/registerにアクセスするとユーザの登録画面が表示されます。

Laravel8ユーザ登録画面
Laravel8ユーザ登録画面

ユーザ登録のregister画面の表示の流れはログインと全く同じです。ログイン画面の流れが理解できていればユーザ登録の画面の流れの理解も容易です。

ユーザがブラウザで/registerにアクセスを行うとLaravel\Fortify\Http\Controllers\RegisteredUserController@createが実行されます。

php artisan route:listを実行し、URLでregisterを確認しその行のAction列を確認することで/registerにアクセスする(GETリクエスト)でRegisteredUserController@createが実行されることがわかります。
fukidashi

RegisteredUserControllerのcreateメソッドを確認するとapp(RegisterViewResponse::class)が実行されることがわかります。


public function create(Request $request): RegisterViewResponse
{
    return app(RegisterViewResponse::class);
}

RegisterViewResponseについてはサービスプロバイダーファイルのJetstreamServiceProvider.phpのbootメソッド中にあるFortify::viewPrefix(‘auth.’)を確認する必要があります。


public function boot()
{
    $this->loadViewsFrom(__DIR__.'/../resources/views', 'jetstream');

    Fortify::viewPrefix('auth.');

//略

viewPrefixメソッドの中身にregisterViewメドッドがあり$prefixには”auth.”が入っています。


public static function viewPrefix(string $prefix)
{
    static::loginView($prefix.'login');
    static::twoFactorChallengeView($prefix.'two-factor-challenge');
    static::registerView($prefix.'register'); //これ
    static::requestPasswordResetLinkView($prefix.'forgot-password');
    static::resetPasswordView($prefix.'reset-password');
    static::verifyEmailView($prefix.'verify-email');
    static::confirmPasswordView($prefix.'confirm-password');
}

registerViewメソッドを確認するとsingletonでサービスコンテナにRegisterViewResponseを登録しています。


public static function registerView($view)
{
    app()->singleton(RegisterViewResponse::class, function () use ($view) {
        return new SimpleViewResponse($view);
    });
}

app(RegisterViewResponse::class)を実行すると引数に$view(=auth.register)が入ったSimpleViewResponseのインスタンスが作成されることがわかります。

ここまでの流れを確認することでユーザがregisterにアクセスするとresource¥views¥auth¥register.blade.phpの中身が表示されることがわかります。

auth.registerの中身について

auth.registerの中身もauth.loginと同様にx-guest-layoutから始まります。x-XXXとついているタグはauth.loginの箇所でも説明した通りBlade Componentsを利用しているのでComponentに対応するファイルviews/vendor/jetstream/components以下のファイルを見ることで確認することができます。

views/vendor/jetstream/components以下のComponentに関連するファイルははphp artisan vendor:publish –tag=jetstream-viewsすることで作成されます。実行しない場合はvendor¥laravel¥jetstream¥resource¥views¥componentsディレクトリを見てください。
fukidashi

ユーザ登録のPOSTリクエスト

ユーザ登録画面が表示される流れと表示されている内容が記述されているファイルを理解することができました。ここではさらにユーザ登録画面(/register)からユーザが入力を行い、POSTリクエスト送信後に実行される処理について確認を行っていきます。

名前付きルート

ユーザ登録画面のviewファイルのregister.blade.phpファイルを確認するとPOSTリクエストはroute(‘register’)に送信されています。


<form method="POST" action="{{ route('register') }}">

route(‘XXX’)は名前付きルートと呼ばれるものでルーティングに固有の名前XXXをつけるとbladeファイル内でrouteメソッドの引数にXXXを入れることでそのURLを表示してくれます。

名前付きルートを利用することでもしアクセス先のURLがregisterから/admin/registerに変更してもBlade側のURLを変更する必要はありません。名前付きルートはさまざまなフレームワークで利用されるいる機能です。
fukidashi

名前付きルートに設定した名前はphp artisan route:listコマンドのName列で確認することができます。名前付きルートregisterは/regisgterであることがわかります。またPOSTリクエストはphp artisan route:listからLaravel\Fortify\Http\Controllers\RegisteredUserController@storeが実行されることもわかります。

RegisteredUserController.phpのStoreメソッド

RegisteredUserController.phpファイルのstoreメソッドは下記の通りです。


public function store(Request $request,
                        CreatesNewUsers $creator): RegisterResponse
{
    event(new Registered($user = $creator->create($request->all())));

    $this->guard->login($user);

    return app(RegisterResponse::class);
}

storeメソッドの中身を見るとユーザの登録(作成)は$user = $creator->create($request->all())だということはコードから簡単に想像できるかと思います。

createメソッドで何を行っているか確認する必要がありますが、Dependency Injectionで利用されているCreateNewUsersはインターフェイスなのでそのファイルの中身を確認してもcreateメソッドの処理はわかりません。

createNewUsers

createメソッドの中身を確認するためにはインターフェイスのcreateNewUsersではなく実際にインスタンス化されるクラスを見つける必要があります。

インターフェイスの中身は実体ファイルを見つけたい場合はまずそのパッケージのサービスプロバイダーファイルを確認しましょう。
fukidashi

サービスプロバイダーファイルであるapp¥Providers¥FortifySserviceProvider.phpファイルのbootメソッドを確認するとFortify::createUsersUsingを見つけることができます。引数にはApp\Actions\Fortify\CreateNewUserが指定されています。


public function boot()
{
    Fortify::createUsersUsing(CreateNewUser::class);
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
    Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
    Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
}

FortifyのcreateUsersUsingメソッドを確認します。singletonでCreateNewUsersの実体がApp\Actions\Fortify\CreateNewUserとしてサービスコンテナに登録されています。


public static function createUsersUsing(string $callback)
{
    return app()->singleton(CreatesNewUsers::class, $callback);
}

RegisteredUserController.phpファイルのインターフェイスのCreatesNewUsersの実体はApp\Actions\Fortify\CreateNewUserであることがわかりました。CreateNewUsersのcreateメソッドはCreateNewUserのcreateメソッドを確認すればいいことになります。

App\Actions\Fortify\CreateNewUserファイルの中身を確認するとユーザ作成のコードが記述されています。バリデーション処理も含まれており、このファイルを更新することでバリデーションの変更も行うことが可能です。


namespace App\Actions\Fortify;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\CreatesNewUsers;

class CreateNewUser implements CreatesNewUsers
{
    use PasswordValidationRules;

    public function create(array $input)
    {
        Validator::make($input, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => $this->passwordRules(),
        ])->validate();

        return User::create([
            'name' => $input['name'],
            'email' => $input['email'],
            'password' => Hash::make($input['password']),
        ]);
    }
}

ユーザ作成後のイベント

ユーザ作成後の処理を確認するためRegisteredUserController.phpを再度確認します。ユーザ作成が行われるとeventメソッドによりRegisteredイベントが実行されていることがわかります。イベントが発行されているということはそのイベントを受け取るリスナーが必ず存在します。


public function store(Request $request,
                        CreatesNewUsers $creator): RegisterResponse
{
    event(new Registered($user = $creator->create($request->all())));

    $this->guard->login($user);

    return app(RegisterResponse::class);
}

Registeredイベントの中身を確認します。引数で受け取った$userを保存しているだけです。


class Registered
{
    use SerializesModels;

    public function __construct($user)
    {
        $this->user = $user;
    }
}

イベントRegisteredが実行されるとリスナー側でどのような処理が実行されるかはEventServiceProvider.phpファイルに記述されています。

EventServiceProvider.phpを確認するとRegisteredイベントに対応する処理はSendEmailVerificationNotificationであることがわかります。


protected $listen = [
    Registered::class => [
        SendEmailVerificationNotification::class,
    ],
];

SendEmailVerificationNotification

SendEmailVerificationNotification.phpファイルはIlluminate\Auth\Listeners\に保存されているので中身を確認します。

リスナーなのでhandleメソッドが実行されます。handleメソッドの中ではEmailでのユーザ認証に関する処理であることがわかります。


class SendEmailVerificationNotification
{
    /**
     * Handle the event.
     *
     * @param  \Illuminate\Auth\Events\Registered  $event
     * @return void
     */
    public function handle(Registered $event)
    {
        if ($event->user instanceof MustVerifyEmail && ! $event->user->hasVerifiedEmail()) {
            $event->user->sendEmailVerificationNotification();
        }
    }
}

デフォルトではFortify.phpの設定ファイルでEmail Valificationの機能をコメントアウトされているのでここの処理は行われません。Email Valificationの機能を利用するためにはFortify.phpファイルのコメントを外して機能を有効化するだけではなく$userがMustVerifyEmailのインスタンスであることも確認しておく必要があります。

参考に以下が設定ファイルのfortify.phpの機能の有効、無効化を行う箇所です。app¥configの下に保存されています。


'features' => [
    Features::registration(),
    Features::resetPasswords(),
    // Features::emailVerification(), //デフォルトではここが無効化されています。
    Features::updateProfileInformation(),
    Features::updatePasswords(),
    Features::twoFactorAuthentication([
        'confirmPassword' => true,
    ]),
],

RegisterResponseの処理

Event処理が行われると$this->guard->login($user)でログイン処理が行われます。ログイン処理についてはここでは割愛します。


public function store(Request $request,
                        CreatesNewUsers $creator): RegisterResponse
{
    event(new Registered($user = $creator->create($request->all())));

    $this->guard->login($user);

    return app(RegisterResponse::class);
}

ログイン処理完了後、app(RegisterResponse::class)が実行されます。RegisterResponseはインターフェイスなのでLaravel\Fortify\Contracts\RegisterResponseの中に処理の記述はありません。

RegisterResponseの処理内容を理解するためにサービスプロバイダーファイルのFortifyServiceProvider.phpを確認する必要があります。

vendor¥laravel¥jetstream¥src¥FortifyServiceProvider.php

FortifyServiceProvider.phpファイルのregisterResponseBindingsメソッドの中でRegisterResponseがsingletonによりサービスコンテナに登録されていることがわかります。storeメソッド内でapp(RegisterResponse::class)を実行するとRegisterResponseが実行されることになります。


protected function registerResponseBindings()
{
//略
    $this->app->singleton(RegisterResponseContract::class, RegisterResponse::class);
//略
}

リダイレクト先の設定

Laravel\Fortify\Http\Responses\RegisterResponseの中身を確認します。wantsJsonメソッドによりrequestがJSONで戻して欲しいかチェックを行っていますがここではfalseになるためリダイレクトが行われます。JSONの場合はHTTPコード201のcreatedが戻されます。


public function toResponse($request)
{
    return $request->wantsJson()
                ? new JsonResponse('', 201)
                : redirect(config('fortify.home'));
}

リダイレクト先は設定ファイルのfortify.phpのfortify.homeによって決まります。

fortify.phpファイルのhomeはデフォルトでは下記のように設定が行われいます。


'home' => RouteServiceProvider::HOME,

RouteServiceProvider.phpのHOMEを見るとdashboardが設定されていることが確認できます。


public const HOME = '/dashboard';

リダイレクト先を変更したい場合はfortifyのhomeを設定すればいいことがわかります。

ルーティングの設定について

login, registerのルーティングの登録がどこで行われているか確認しておきましょう。

サービスプロバイダーファイルのvendor¥laravel¥jetstream¥src¥FortifyServiceProvider.phpのbootメソッド内のconfigureRoutesを確認します。


public function boot()
{
    $this-<configurePublishing();
    $this-<configureRoutes();
}        

configureRoutesではルーティングの登録が行われています。loadRoutesFormで指定されているroutes.phpファイルはvendor/laravel/fortify/src/routes/routes.phpです。


protected function configureRoutes()
{
    if (Fortify::$registersRoutes) {
        Route::group([
            'namespace' => 'Laravel\Fortify\Http\Controllers',
            'domain' => config('fortify.domain', null),
            'prefix' => config('fortify.path'),
        ], function () {
            $this-<loadRoutesFrom(__DIR__.'/../routes/routes.php');
        });
    }
}      

routes.phpファイルの中身を確認すると/loginや/registerのルーティング情報が記述されています。php artisan list:routeコマンドで確認していたコントローラー名AuthenticatedSessionController、メソッド名createもこのファイルから確認することができます。


Route::group(['middleware' => config('fortify.middleware', ['web'])], function () {
    // Authentication...
    Route::get('/login', [AuthenticatedSessionController::class, 'create'])
        ->middleware(['guest'])
        ->name('login');

    $limiter = config('fortify.limiters.login');

    Route::post('/login', [AuthenticatedSessionController::class, 'store'])
        ->middleware(array_filter([
            'guest',
            $limiter ? 'throttle:'.$limiter : null,
        ]));
//略   

ここまで読み進めてくれた方であればLaravel8の認証に関する理解が深まったのではないかと思います。これでJetStreamの認証機能を安心して利用できるのではないでしょうか。少し長めの文章なのでそうなってくれていればとてもうれしいです。