🐷

Laravel をバックエンドとして Laravel Sanctum を使用して SPA 認証機能を実装する。

2023/12/08に公開

概要

フロントを React で開発している。そこにバックエンド開発として Laravel を採用した。そこで認証機能を Laravel Sanctum を使用して SPA 認証機能を実装する。
React は localhost:3000, Laravel は localhost:8000 を使用している。

環境

  • Windows 10 Home
  • php: 8.0.10
  • composer: 2.1.7
  • Laravel: ^8.75

Laravel の認証機能

今回は Laravel Sanctum を使用する。

Laravel Sanctum の準備

https://readouble.com/laravel/8.x/ja/sanctum.html
composer.json の require のリストに laravel/sanctum が記載がない場合は以下を実行

composer require laravel/sanctum

次に、初期設定では Sanctum の設定ファイル等が非表示になっているため Artisan コマンドを使用して該当ファイルを表示可能にする。

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

今回は SPA認証のみを行うため、APIトークンを格納するためのテーブルを作成する必要はない。
また、上記で作成された database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php ファイルは不要なので削除する。
また、上記のマイグレーションファイルを削除しただけでは、マイグレーション実行時に personal_access_tokens のテーブルが作成されてしまうため、これを無効化する必要がある。
その概要については以下を参考にする。
https://qiita.com/ucan-lab/items/6a3481b389a886115ada

最後に app/Http/Kernel.php ファイル内の api ミドルウェアグループ内に以下を追記する。

Kernel.php
'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, // 追記
    'その他'
],

SPA認証の実装

はじめにファーストパーティドメインの設定をする必要がある。この設定はデフォルトで config/sanctum.php の stateful に記載されており、デフォルトでは下記のようになっている。

sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),

今回、フロントエンド開発に使用してる React は localhost:3000 で接続することができるので設定を変更する必要はないが、定義されていない FQDN を使用する場合は別途、以下を参考に環境ファイルに定義する必要がある。

SANCTUM_STATEFUL_DOMAINS={FQDN}

次に、双方のアプリケーションに対してcorsの設定を行う必要がある。
Laravel 側のcorsの設定は config/cors.php に記載されており、このファイル内の supports_credentials を true に変更する必要がある。

cors.php
<?php
return [
    ... ,
    'supports_credentials' => true,
]

また、React 側の設定は、axios を使用する場合、デフォルトでは withCredentials の値が false になっているので、これを true に変更する。今回は、axios をインスタンス化する際に設定しておく。

axios.create({
    ... ,
    withCredentials: true,
})

Laravelアプリケーションのセッションクッキードメイン設定をします。
アプリケーションのconfig/session.php設定ファイル内でドメインの先頭に.を付けます。

session.php
'domain' => '.domain.com',

※ localhostで開発している場合は設定する必要はない。

コンソールにこのように表示された場合は成功

{data: '', status: 204, statusText: 'No Content', headers: {…}, config: {…}, …}

Laravel Fortify の準備

https://readouble.com/laravel/8.x/ja/fortify.html
はじめに、Fortify をインストールする。

composer require laravel/fortify

次に、Laravel Sanctum の時と同様に初期設定では Fortify の設定ファイル等が非表示になっているため Artisan コマンドを使用して該当ファイルを表示可能にする。

php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"

ここで、config/app.php 内の providers 配列内に App\Providers\FortifyServiceProvider クラスが登録されていることを確認する。仮に登録されていない場合は以下を追記する。

app.php
<?php

return
    ... ,
    'providers' => [
        ... ,
	App\Providers\FortifyServiceProvider::class, // 追記	
    ]

最後に、データベースをマイグレーションする。

php artisan migrate

Laravel Fortify でログイン

まず、config/fortify.php 内の View の設定が true になっているので、false に変更する。

fortify.php
'views' => false,

これによって Laravel 側でログインや登録画面を表示するためのルートが削除される。
実際に、php artisan route:list > routes.txt コマンドで定義されているルートを書き出して確認すると true から false に変更するにあたって

|        | GET|HEAD | login                                    | login                           | Laravel\Fortify\Http\Controllers\AuthenticatedSessionController@create            | web                                                       |
|        | GET|HEAD | register                                 | register                        | Laravel\Fortify\Http\Controllers\RegisteredUserController@create                  | web                                                       |

などのルートが定義されていない状態になっていることが確認できる。

Discussion