Laravelでログイン履歴・ログアウト履歴をDBに記録する方法をご紹介します。
「Laravel Breeze」という認証機能をインストールしている場合の手順になります。
自分で設定するときに試行錯誤したため、備忘録です😉
事前準備
1. マイグレーションを実行して、DBを作成します。
php artisan migrate
データーベースとテーブルが作成されます。
2. ログイン履歴・ログアウト履歴を記録用のテーブルを作成するために、
マイグレーションファイルを作成します。
php artisan make:migration create_user_login_logs_table
3. 「手順2」で作成したマイグレーションファイルに、コードを追記します。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('user_login_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('email')->nullable();
$table->timestamp('login_at')->nullable();
$table->timestamp('logout_at')->nullable();
$table->string('ip_address')->nullable();
$table->string('status')->nullable();
$table->string('user_agent')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('user_login_logs');
}
};
4. マイグレーションを実行します。
php artisan migrate
5. テーブルが作成できました。
6. 「構造」→ 「user_id」で「変更」をクリックします。
7. 「Null」にチェックをいれて、保存します。
アカウントを2つ作成しておく
テスト用として「users」テーブルに、アカウントを2つ作成します。
私は 「http://localhost/testlaravel/public/register」にアクセスして、
アカウントを作成しました。
イベントとリスナーを生成する
1. ファイルを5つ生成するために、コードを上から順番に実行します。
php artisan make:event UserLoggedIn
php artisan make:event UserLoggedOut
php artisan make:listener LogUserLogin --event=UserLoggedIn
php artisan make:listener LogUserLogout --event=UserLoggedOut
php artisan make:listener LogFailedLogin
2. 「手順1」で作成したファイルを編集していきます。
use文の追加も忘れずに!
① app\Events\UserLoggedIn.php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
class UserLoggedIn
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $loginSuccess;
public $email;
public function __construct(User $user, $loginSuccess, $email)
{
$this->user = $user;
$this->loginSuccess = $loginSuccess;
$this->email = $email;
}
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
② app\Events\UserLoggedOut.php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
class UserLoggedOut
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $email;
public function __construct(User $user, $email)
{
$this->user = $user;
$this->email = $email;
}
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
③ app\Listeners\LogUserLogin.php
<?php
namespace App\Listeners;
use App\Events\UserLoggedIn;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Request;
class LogUserLogin
{
public function __construct()
{
//
}
public function handle(UserLoggedIn $event): void
{
$user = $event->user;
$loginSuccess = $event->loginSuccess;
$email = $event->email;
$userAgent = Request::header('User-Agent');
$ipAddress = Request::ip();
DB::table('user_login_logs')->insert([
'user_id' => $user->id,
'email' => $email,
'login_at' => now(),
'ip_address' => $ipAddress,
'user_agent' => $userAgent,
'status' => $loginSuccess ? 'success' : 'failed',
'created_at' => now(),
'updated_at' => now(),
]);
}
}
④ app\Listeners\LogUserLogout.php
<?php
namespace App\Listeners;
use App\Events\UserLoggedOut;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Request;
class LogUserLogout
{
public function __construct()
{
//
}
public function handle(UserLoggedOut $event): void
{
$user = $event->user;
$email = $event->email;
$userAgent = Request::header('User-Agent');
$ipAddress = Request::ip();
DB::table('user_login_logs')->insert([
'user_id' => $user->id,
'email' => $email,
'logout_at' => now(),
'ip_address' => $ipAddress,
'user_agent' => $userAgent,
'created_at' => now(),
'updated_at' => now(),
]);
}
}
⑤ app\Listeners\LogFailedLogin.php
<?php
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Request;
use App\Models\User;
class LogFailedLogin
{
public function __construct()
{
//
}
public function handle(object $event): void
{
// ログイン試行の失敗情報を取得
$credentials = $event->credentials;
$username = $credentials['email'];
$userAgent = Request::header('User-Agent');
$ipAddress = Request::ip();
// 既存ユーザーの場合はユーザーIDを取得、それ以外はnull
$user = User::where('email', $username)->first();
$userId = $user ? $user->id : null;
DB::table('user_login_logs')->insert([
'user_id' => $userId,
'email' => $username,
'login_at' => now(),
'ip_address' => $ipAddress,
'user_agent' => $userAgent,
'status' => 'failed',
'created_at' => now(),
'updated_at' => now(),
]);
}
}
EventServiceProvider.php 編集
app\Providers\EventServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use JeroenNoten\LaravelAdminLte\Events\BuildingMenu;
use App\Events\UserLoggedIn;
use App\Events\UserLoggedOut;
use App\Listeners\LogUserLogin;
use App\Listeners\LogUserLogout;
use Illuminate\Auth\Events\Failed;
use App\Listeners\LogFailedLogin;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
UserLoggedIn::class => [
LogUserLogin::class,
],
UserLoggedOut::class => [
LogUserLogout::class,
],
Failed::class => [
LogFailedLogin::class,
],
];
public function boot(): void
{
//
}
public function shouldDiscoverEvents(): bool
{
return false;
}
}
AuthenticatedSessionController.php 編集
app\Http\Controllers\Auth\AuthenticatedSessionController.php
このファイルは「Laravel Breeze」という認証機能をインストールしている場合に、
存在するファイルです。
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
use App\Events\UserLoggedIn;
use App\Events\UserLoggedOut;
use App\Listeners\LogUserLogin;
use App\Listeners\LogUserLogout;
class AuthenticatedSessionController extends Controller
{
public function create(): View
{
return view('auth.login');
}
public function store(LoginRequest $request): RedirectResponse
{
$request->authenticate();
$user = $request->user();
$email = $request->input('email');
event(new UserLoggedIn($user, true, $email)); // ログイン成功
$request->session()->regenerate();
return redirect()->intended(RouteServiceProvider::HOME);
}
public function destroy(Request $request): RedirectResponse
{
$user = $request->user();
$email = $user->email;
Auth::guard('web')->logout();
// ユーザーがログアウトしたことをイベントとして発火
event(new UserLoggedOut($user, $email));
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}
動作確認
ログイン成功時の動作
1. 「test1@test.com」でログインします。
2. DBにログインした日時などの情報が保存されます。
ログインが成功した場合は「status」に「success」と表示されます。
3. ログアウトすると、ログアウトした日時が保存されます。
ログアウト時の「status」は NULL と表示されます。
「http://localhost」のアクセスの場合は「ip_address」に「::1」と表示されるようです。
レンタルサーバーなどのアクセスの場合は、通常のIPアドレスが取得できました。
ログイン失敗時の動作①
1. 「users」テーブルに存在するアカウントでパスワードを間違えて、ログイン失敗した場合
2. DBにログインが失敗した日時などの情報が保存されます。
ログインが失敗した場合は「status」に「failed」と表示されます。
ログイン失敗時の動作②
1. 「users」テーブルに存在しないアカウントでログインしようとした場合
2. DBにログインが失敗した日時などの情報が保存されます。
ログインが失敗した場合は「status」に「failed」と表示されます。
「user_id」に NULL と表示されるので、
「users」テーブルに存在しないメールアドレスであることが分かります。
環境:Laravel 10
この記事がお役に立ちますと幸いです。
「Laravelの教科書 バージョン10対応」
最新Laravel 10の機能やアップデート内容を網羅しながら、スキルアップを図る!
「オールカラー」解説で、初心者の方でも迷わずに学ぶことができます。
コードだけで無く「なぜそうなるか」を丁寧に説明してくれます。オススメの1冊です👌