Twitterやその他SNSのようにメールアドレスとユーザーIDのどちらかとパスワードを入力することでログインできるようにカスタマイズする方法です。
Contents
環境
- Laravel 9x
- Fortify
https://readouble.com/laravel/9.x/ja/fortify.html
ユーザーテーブルにカラムを追加する
ユーザーテーブルにユーザーIDを保存するためのカラムを追加します。
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name')->nullable();
$table->string("account_id")->unique()->comment('アカウントID'); #追加
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
コントローラー作成
ログイン処理のためのコントローラーをapp/Http/Controllers/Auth/LoginController.phpなどにして作成します。
Laravel Fortifyのデフォルトではvendor/laravel/fortify/src/Http/Controllers/AuthenticatedSessionController.phpにログインとログアウトの処理が記載されているのでそれをコピペして作成したLoginController.phpに貼り付けます。
ルーティング追記
Laravel Fortifyではカスタマイズがなければ特にルーティングを新たに書かなくても問題ないですが
今回はLoginController.phpを新たに作成したのでルーティングを書いてあげる必要があります。
Route::group([
'namespace' => 'App\Http\Controllers\Auth',
], function () {
Route::post('/login', 'LoginController@store');
Route::post('/logout', 'LoginController@destroy');
});
LoginControllerの内容を修正
先ほどコピペしたAuthenticatedSessionController.phpの内容を修正します。
ログインに関する処理はstoreメソッドに書かれていますのでここをカスタマイズします。
<?php
namespace App\Http\Controllers\Auth; //変更
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Routing\Pipeline;
use Laravel\Fortify\Actions\AttemptToAuthenticate;
use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled;
use Laravel\Fortify\Actions\PrepareAuthenticatedSession;
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
use Laravel\Fortify\Contracts\LoginResponse;
use Laravel\Fortify\Contracts\LoginViewResponse;
use Laravel\Fortify\Contracts\LogoutResponse;
use Laravel\Fortify\Features;
use Laravel\Fortify\Fortify;
use App\Http\Requests\LoginRequest; //変更
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
//省略
public function store(LoginRequest $request)
{
//追記
$account_id = $request->input('account_id');
$password = $request->input('password');
if (preg_match('/^[a-z0-9._+^~-]+@[a-z0-9.-]+$/i', $account_id)) {
$credentials = ['email' => $account_id, 'password' => $password];
} else {
$credentials = ['account_id' => $account_id, 'password' => $password];
}
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return app(LoginResponse::class);
}
return $this->loginPipeline($request)->then(function ($request) {
return app(LoginResponse::class);
});
}
protected function loginPipeline(LoginRequest $request)
{
if (Fortify::$authenticateThroughCallback) {
return (new Pipeline(app()))->send($request)->through(array_filter(
call_user_func(Fortify::$authenticateThroughCallback, $request)
));
}
if (is_array(config('fortify.pipelines.login'))) {
return (new Pipeline(app()))->send($request)->through(array_filter(
config('fortify.pipelines.login')
));
}
return (new Pipeline(app()))->send($request)->through(array_filter([
config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,
Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,
AttemptToAuthenticate::class,
PrepareAuthenticatedSession::class,
]));
}
//省略
}
メールアドレスかどうか判別する
preg_match()関数で正規表現を使いリクエストで飛んできた値がメールアドレスかどうか判別します。
メールアドレスであればemailメールアドレスでなければaccount_idとしてキー/値ペアの配列を作成します。
Auth::attempt()メソッドは引数の値をuserテーブルと照合し、OKの時点でログイン状態にして返してくれます。
if (preg_match('/^[a-z0-9._+^~-]+@[a-z0-9.-]+$/i', $account_id)) {
$credentials = ['email' => $account_id, 'password' => $password];
} else {
$credentials = ['account_name' => $account_id, 'password' => $password];
}
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return app(LoginResponse::class);
}
LoginRequestを作成
LoginRequestを編集します。
デフォルトのままではFortify::username()がemailとなっていますのでリクエストの値にemailがなければバリデーションではじかれてしまいます。
Laravel Fortifyのデフォルトの記述
public function rules()
{
return [
Fortify::username() => 'required|string',
'password' => 'required|string',
];
}
LoginRequestをカスタマイズする
ログイン処理時にaccount_idとpasswordを飛ばしたいので以下の様に変更します。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class LoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'account_id' => 'required|string',
'password' => 'required|string',
];
}
/**
* バリデーション項目名定義
* @return array
*/
public function attributes()
{
return [
'account_id' => "アカウント名またはメールアドレス",
];
}
}