Laravel 11で認証機能を0から自作する 【Part.3 ログイン機能】
目次
Laravel 11で認証機能を0から自作する – ログインとログアウト機能の実装
前回の記事では、ユーザー登録機能を実装しました。今回は、登録したユーザーでログインおよびログアウトができるように機能を実装します。
1. ログイン用コントローラクラスの作成
まず、ユーザーがログインするためのコントローラを作成します。このコントローラでは、ログインフォームの表示と、ユーザーの認証処理を行います。
php artisan make:controller Auth/LoginController
app/Http/Controllers/Auth/LoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
public function __construct()
{
$this->middleware('guest'); // ログインしていないユーザーのみがアクセス可能
}
/**
* ログインフォームを表示する
*
* @return \Illuminate\View\View
*/
public function showLoginForm()
{
return view('auth.login');
}
/**
* ユーザーのログイン処理を実行する
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function login(Request $request)
{
// 1. リクエストのデータを検証する
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
// 2. 認証を試みる
if (Auth::attempt($credentials, $request->filled('remember'))) {
// 認証に成功したら、セッションを再生成する
$request->session()->regenerate();
// ダッシュボードにリダイレクトする
return redirect()->intended('dashboard');
}
// 認証に失敗した場合は、ログインページにリダイレクトする
return back()->withErrors([
'email' => 'ログイン情報が正しくありません。',
])->onlyInput('email');
}
}
ここで、login
メソッドの処理について詳しく見ていきましょう。
- リクエストのデータの検証
ユーザーから送信されたデータ(email
とpassword
)を検証します。検証にはvalidate
メソッドを使用し、指定されたバリデーションルール(required
およびemail
)に基づいてチェックを行います。 - 認証
Authファサードの機能の一つである、Auth::attempt()
メソッドを使用して、ユーザーの認証を試みます。このメソッドは、渡された認証情報($credentials
)をもとに、usersテーブル内のユーザーを検索し、認証が成功した場合にはtrue
を返します。 - セッションの再生成
認証に成功した場合、$request->session()->regenerate()
メソッドを呼び出してセッションIDを再生成します。これにより、セッション固定攻撃(Session Fixation Attack)のリスクを減らし、セキュリティを強化します。 - リダイレクト処理
認証が成功した場合、ユーザーをダッシュボードページ(/dashboard
)にリダイレクトします。もし、認証に失敗した場合は、ログインページにリダイレクトし、エラーメッセージを表示します。
また、コンストラクタ内では、※ guest
ミドルウェアを適用することで、このコントローラの処理の実行を非ログインユーザーのみに限定し、ログイン中のユーザーがログインページ(/login
)にアクセスしようとした場合、自動的にダッシュボードページ(/dashboard
)にリダイレクトされる仕組みとなっています。
guest
ミドルウェアの設定はLaravel 11 ではデフォルトで以下で行われています。
vendor/laravel/framework/src/Illuminate/Foundation/Configuration/Middleware.php
https://github.com/laravel/framework/blob/b7c628776754a7d861dd48ff18768e1c1f2d5f5f/src/Illuminate/Foundation/Configuration/Middleware.php#L734
ルーティングでミドルウェアを設定する場合
クラスのコンストラクタで行わなくても、ユーザ登録機能(/register)で行なっているときと同様、後述のルーティングの箇所で設定を行なっても問題ありません。
Route::get('login', [LoginController::class, 'showLoginForm'])->middleware('guest')->name('login');
2. ログアウト用コントローラクラスの作成
次に、ユーザーのログアウト処理を行うためのコントローラを作成します。
php artisan make:controller Auth/LogoutController
app/Http/Controllers/Auth/LogoutController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth; // Authファサードのインポート
use Illuminate\Http\Request;
class LogoutController extends Controller
{
/**
* ログアウト処理を実行する
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function logout(Request $request)
{
// 1. ユーザーをログアウトさせる
Auth::logout();
// 2. セッションを無効にする
$request->session()->invalidate();
// 3. 新しいCSRFトークンを再生成する
$request->session()->regenerateToken();
// 4. トップページにリダイレクトする
return redirect('/');
}
}
logoutメソッドの詳細
- セッションの無効化
invalidate()
: 現在のセッションを終了し、すべてのセッションデータを削除します。これにより、ユーザーのログアウトが確実に行われ、セッションの再利用が防止されます。 - CSRFトークンの再生成
regenerateToken()
: セッションを無効化するだけでは、古いCSRFトークンが再利用されるリスクがあります。トークンを再生成することで、トークンの使い回しによる攻撃を防ぎ、セッション無効化後の安全性をさらに高めることができます。
3. ログインフォームのテンプレート作成
ログインフォームを表示するテンプレートを作成します。
resources/views/auth/login.blade.php
@extends('layouts.app')
@section('title', 'ログイン')
@section('content')
<h2 class="text-center mb-4">ログイン</h2>
<form action="{{ route('login') }}" method="POST">
@csrf
<div class="mb-3">
<label class="form-label" for="email">メールアドレス</label>
<input id="email" class="form-control" name="email" type="email" value="{{ old('email') }}" autofocus />
@error('email')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label class="form-label" for="password">パスワード</label>
<input id="password" class="form-control" name="password" type="password" />
@error('password')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="mb-3 form-check">
<input id="remember" class="form-check-input" name="remember" type="checkbox" />
<label class="form-check-label" for="remember">ログイン情報を記憶する</label>
</div>
<button class="btn btn-primary w-100" type="submit">ログイン</button>
</form>
@endsection
4. ログイン/ログアウト リンク追加
トップページにログインページへのリンクを追加します。
resources/views/index.blade.php
@extends('layouts.app')
@section('title', 'トップページ')
@section('content')
<h2 class="text-center mb-4">トップページ</h2>
@auth
<p class="text-center">ログイン中: {{ Auth::user()->name }}</p>
@endauth
<div class="d-flex justify-content-center">
<a href="{{ route('register') }}" class="btn btn-outline-primary mx-2">ユーザー登録</a>
@auth
<a href="{{ route('dashboard') }}" class="btn btn-primary mx-2">ダッシュボード</a>
@else
<a href="{{ route('login') }}" class="btn btn-outline-primary mx-2">ログイン</a>
@endauth
</div>
@endsection
ダッシュボードページにログアウトリンクを追加します。
resources/views/dashboard.blade.php
@extends('layouts.app')
@section('title', 'ダッシュボード')
@section('content')
<h2 class="text-center mb-4">ダッシュボード</h2>
<p class="text-center">ログイン中: {{ Auth::user()->name }}</p>
<div class="d-flex justify-content-center">
<a href="{{ route('home') }}" class="btn btn-outline-secondary mx-2">トップページに戻る</a>
</div>
<form class="text-center mt-4" action="{{ route('logout') }}" method="POST" class="d-inline">
@csrf
<button type="submit" class="btn btn-danger mx-2">ログアウト</button>
</form>
@endsection
5. ルーティング設定
ログイン/ログアウトのルーティング設定を行います。
routes/web.php
今回新たに追加したルーティングをこれまでの実装に追記してください。
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\Auth\RegisterController;
use App\Http\Controllers\Auth\LoginController;
use App\Http\Controllers\Auth\LogoutController;
// トップページのルート
Route::get('/', [HomeController::class, 'index'])->name('home');
// ダッシュボードのルート(ログインが必要)
Route::get('/dashboard', [HomeController::class, 'dashboard'])->middleware('auth')->name('dashboard');
// ユーザー登録のルート
Route::get('register', [RegisterController::class, 'showRegistrationForm'])->name('register');
Route::post('register', [RegisterController::class, 'register']);
// ログインのルート
Route::get('login', [LoginController::class, 'showLoginForm'])->name('login');
Route::post('login', [LoginController::class, 'login']);
// ログアウトのルート
Route::post('logout', [LogoutController::class, 'logout'])->name('logout');
実装が完了したら、実際に/login
へアクセスし、ログインが行えるか確認します。
前回の記事で、ユーザ登録を行ってそのままログインしている状態の場合は、ダッシュボードページが表示されるので、ログアウト/logout
から動作を確認することができます。