Laravel8 laravel uiからfortifyに移行は可能
2020-09-22
(zennはタイトルに/が書けない?)
旧バージョンからLaravel8にアップグレードしたプロジェクトが想定。
fortifyに移行できれば非推奨になったuiを削除できる。
Fortify
フロントエンドにとらわれないバックエンド認証機能。
uiのauth-backendやstubs/Auth辺りに相当。フロントは自分で実装する必要がある。
Livewire or Inertiaで実装してるのがJetstream。
この記事でやろうとしてることは、uiのviewをフロントとして使う。
プロジェクトの準備
Laravel8で一から作る。
laravel new laravel8-ui-to-fortify
cd laravel8-ui-to-fortify
composer require laravel/ui
php artisan ui vue --auth
npm i
npm run prod
php artisan migrate
DBはSQLiteを使うとか細かい所は省略。
これでLaravel8のwelcomeページとuiのログイン画面を持ったプロジェクトができあがる。
login
やregister
ルートは存在するのでLaravel8のwelcomeページでも問題なく動く。
ユーザー登録しておく。登録後はログアウト。
laravel/ui アンインストール
routes/web.phpのAuth::routes();
とcomposer.jsonからlaravel/uiを削除。
laravel/fortify インストール
composer require laravel/fortify
php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"
php artisan migrate
ここまででログインしようとしてもTarget [Laravel\Fortify\Contracts\LoginViewResponse] is not instantiable.
のエラー。
解決方法は
config/app.php
にApp\Providers\FortifyServiceProvider::class,
追加。
そのFortifyServiceProvider@bootにFortify::viewPrefix('auth.');
追加。
JetstreamでインストールするとFortify::viewPrefix()
はJetstream内で実行されてるのでなかなか原因が分からなかった。
Fortifyにviewは含まないのでどういうviewを使うかは利用する側で指定。これの理解が一番重要だった。
この時点でユーザー登録とログインとhome表示とログアウトは可能。意外とスムーズ。
Fortify::viewPrefix('auth.')の処理を追う
loginView('auth.login')
へ。
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');
}
サービスコンテナへ登録。LoginViewResponseだったらSimpleViewResponseを返す。
public static function loginView($view)
{
app()->singleton(LoginViewResponse::class, function () use ($view) {
return new SimpleViewResponse($view);
});
}
SimpleViewResponse
はここ。
public function toResponse($request)
{
return is_callable($this->view) && ! is_string($this->view)
? call_user_func($this->view, $request)
: view($this->view, ['request' => $request]);
}
最終的には見慣れたview()
に辿り着く。
view('auth.login')
を表示してるだけなのでuiと同じと分かる。
public function showLoginForm()
{
return view('auth.login');
}
こんな回りくどいことをしてるのはカスタマイズできるように。
ログインは動くけどパスワードリセットは動かないのでFortifyServiceProvider@bootでviewの指定。
Fortify::viewPrefix('auth.');
Fortify::requestPasswordResetLinkView('auth.passwords.email');
Fortify::resetPasswordView('auth.passwords.reset');
Fortify::confirmPasswordView('auth.passwords.confirm');
Fortify::verifyEmailView('auth.verify');
逆にviewのファイル名を変更してもいい。
これでlaravel/uiの機能をlaravel/fortifyに置き換えられた。
今回はuiのviewを使ったけど完全に独自のviewを使う場合も同じ。
Fortify単体+独自viewでいろいろ作って欲しいのがLaravel開発者の想定?
JetstreamはLaravel公式が用意したview。
という所まで分かってくるとJetstreamの立ち位置が分かる。
Fortifyのためのviewを提供するcomposerパッケージも作れるな。
追記:試しに作った
- https://github.com/kawax/fortify-uikit
- https://github.com/kawax/fortify-bulma
- https://github.com/kawax/fortify-bootstrap4
本格的に作るならインストールコマンドでJetstreamと同じようなことをするけどこれはviewPrefix()で指定するviewだけ。
Fortify::viewPrefix()はパッケージ側で実行せずプロジェクト側のFortifyServiceProviderで指定。
滅多にないだろうけど複数のパッケージをインストールしたままどれを使うかを選べるように。
不要な機能をオフ
config/fortify.php
で使わない機能をオフ。
'features' => [
Features::registration(),
Features::resetPasswords(),
// Features::emailVerification(),
//Features::updateProfileInformation(),
//Features::updatePasswords(),
//Features::twoFactorAuthentication([
// 'confirmPassword' => true,
//]),
],
uiにはなかったのでオフにしてるけどviewさえ用意すれば使える。
reset.balde.php
細かい修正。
<input type="hidden" name="token" value="{{ $token }}">
↓
<input type="hidden" name="token" value="{{ $request->route('token') }}">
{{ $email ?? old('email') }}
↓
{{ old('email', $request->email) }}
他にもあるかも。
Actions
ユーザー登録時の処理を変更したいとか細かいことはapp/Actions/Fortify/
のファイルで。
app/Http/Controllers/Auth/
は削除していい。
URL
パスワードリセットなどのURLが変わってるけど影響はないはず。ルートは変わってないので。
register,loginが変わってなければ問題ない。
終わり
uiからfortifyに移行はできる。uiを使い続けなくていいと分かって安心。
Discussion