Laravelの認証ログイン時にデータベースへ最終ログイン日時の書き込みを行う
- 公開日
- 更新日
- カテゴリ:Laravel
- タグ:PHP,Laravel,migration,ServiceProviders,Events,Listeners,Auth
Laravel の Auth認証機能を使うと、ログインなどのユーザ管理機能を素早く導入できますが、その機能と情報は必要最小限になっています。
ただし、Laravel の認証機能は固定化された機能ではなく、都度必要な機能を拡張することが可能です。
という事で今回は、管理機能でもよく使われる、ログインする毎にユーザ情報へ最終ログインの記録を行う機能を実装します。
Contents
開発環境
今回の開発環境は以下の通りです。
- Linux CentOS 7
- Apache 2.4
- MySQL 5.7
- PHP 7.1/7.2
- Laravel
Laravel のバージョンに関しては 5.6/5.5/5.4/5.3 にて動作確認済みです。
また、laravel のソースディレクトリを「laravel/」とします。
基本的な認証機能は導入済みである前提で進めますので、導入までに関しては
Laravel の認証機能でログイン/ユーザ登録/パスワードリセットなどの管理画面を一撃構築する(基本&入門編)
を確認してください。
最終ログインカラムの作成
まずは最終ログイン日時を記録するためのカラムを users テーブルに作成します。
laravel ルートディレクトリへ移動し、以下の artisan コマンドを叩いてマイグレーションファイルを生成します。
# Laravel ルートディレクトリへ移動する
cd /path/to/laravel
# artisan コマンドでマイグレーションファイルを生成する
php artisan make:migration add_column_last_login_at_users_table --table=users
# 実行結果
[deom@localhost laravel]# php artisan make:migration add_column_last_login_at_users_table --table=users
Created Migration: 2019_04_14_133657_add_column_last_login_at_users_table
マイグレーションファイルは laravel/database/migrations 配下に生成されます。
laravel
├─ database
│ ├─ migrations
│ │ ├─ 2014_10_12_000000_create_users_table.php
│ │ ├─ 2014_10_12_100000_create_password_resets_table.php
│ │ └─ 2019_04_14_133657_add_column_last_login_at_users_table.php
- laravel/database/migrations/2019_04_14_133657_add_column_last_login_at_users_table.php
-
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class AddColumnLastLoginAtUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { // }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { // }); } }
生成したマイグレーションファイルを、以下のように記述します。
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddColumnLastLoginAtUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->timestamp('last_login_at')->nullable()->after('remember_token')->comment('最終ログイン');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('last_login_at');
});
}
}
最終ログインを格納するカラム名を last_login_at とし、null を許容する timestamp 型として、remember_token カラムの後ろに作成する記述になっています。
それでは、マイグレーションを実行し、テーブルにカラムを追加します。
# Laravel ルートディレクトリへ移動する
cd /path/to/laravel
# artisan コマンドでマイグレーションを実行する
php artisan migrate
# 実行結果
[demo@localhost laravel]# php artisan migrate
Migrating: 2019_04_14_133657_add_column_last_login_at_users_table
Migrated: 2019_04_14_133657_add_column_last_login_at_users_table
users テーブルに last_login_at カラムが追加されました。
mysql> show columns from users;
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| password | varchar(255) | NO | | NULL | |
| remember_token | varchar(100) | YES | | NULL | |
| last_login_at | timestamp | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
イベントリスナの作成
ここからは最終ログインを書き込む処理を Laravel に実装していきますが、イベント&リスナを使って進めていきます。
まずは、イベントとリスナを登録します。 EventServiceProvider.php に以下を追記します。
- laravel/app/Providers/EventServiceProvider.php
-
<?php namespace App\Providers; use Illuminate\Support\Facades\Event; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ 'App\Events\Event' => [ 'App\Listeners\EventListener', ], // ログイン時にイベントを発行 'App\Events\Logined' => [ // 最終ログインを記録するリスナー 'App\Listeners\LastLoginListener', ], ]; /** * Register any events for your application. * * @return void */ public function boot() { parent::boot(); } }
ログイン時にイベントを発行する Logined イベントと、最終ログインを記録する LastLogin リスナーを登録しています。
Laravel ルートディレクトリへ移動し、以下の artisan コマンドを叩き、イベントとリスナファイルを生成します。
# laravel ルートディレクトリへ移動
cd /path/to/laravel
# artisan コマンドでイベントとリスナファイルを生成する
php artisan event:generate
# 実行結果
[demo@localhost laravel]# php artisan event:generate
Events and listeners generated successfully!
生成されたファイルはそれぞれ、laravel/app/Events と laravel/app/Listeners に配置されます。
laravel
├─ app
│ ├─ Events
│ │ ├─ Logined.php
│ │ └─ Event.php
│ ├─ Listeners
│ │ ├─ EventListener.php
│ │ └─ LastLoginListener.php
今回、イベントクラスに関しては今回は生成されたままで追記は行いません。リスナクラスには、最終ログインを記録する処理を handle() メソッドに記述しています。
- laravel/app/Events/Logined.php
-
<?php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Queue\SerializesModels; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; /** * ログイン完了時に発火するイベントクラス * Class Logined * @package App\Events */ class Logined { use Dispatchable, InteractsWithSockets, SerializesModels; /** * Create a new event instance. * * @return void */ public function __construct() { // } /** * Get the channels the event should broadcast on. * * @return \Illuminate\Broadcasting\Channel|array */ public function broadcastOn() { return new PrivateChannel('channel-name'); } }
- laravel/app/Listeners/LastLoginListener.php
-
<?php namespace App\Listeners; use App\Events\Logined; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Facades\Auth; use Carbon\Carbon; /** * ログイン完了時に発火するイベントをキャッチするリスナークラス * Class LastLoginListener * @package App\Listeners */ class LastLoginListener { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param Logined $event * @return void */ public function handle(Logined $event) { $user = Auth::user(); $user->last_login_at = Carbon::now(); $user->save(); } }
ログインコントローラでの発火処理
最後に、ログイン認証後にイベントを発火させる記述を行います。
Laravel の認証機能では LoginController がログイン処理を担っているので、ここに実装していきます。
- laravel/app/Http/Controllers/Auth/LoginController.php
-
<?php namespace App\Http\Controllers\Auth; use Illuminate\Http\Request; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\AuthenticatesUsers; use App\Events\Logined; class LoginController extends Controller { /* |-------------------------------------------------------------------------- | Login Controller |-------------------------------------------------------------------------- | | This controller handles authenticating users for the application and | redirecting them to your home screen. The controller uses a trait | to conveniently provide its functionality to your applications. | */ use AuthenticatesUsers; /** * Where to redirect users after login. * * @var string */ protected $redirectTo = '/account'; /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('guest')->except('logout'); } /** * ログイン認証後の処理 * @param Request $request * @param $user */ protected function authenticated(Request $request, $user) { // ログインイベントを発火させ最終ログイン日時を記録する event(new Logined()); } }
AuthenticatesUsers トレイトの authenticated() メソッドをオーバーライドしている形になります。これによってログイン認証後にイベントが発火し、最終ログイン日時がデータベースへ更新されます。
動作確認
それでは動作確認を行ってみます。
http://YOUR-DOMAIN/login
から実際にログインを行い、最終ログイン日時が更新されるか確認します。
mysql> select id, name, last_login_at from users;
+----+--------+---------------------+
| id | name | last_login_at |
+----+--------+---------------------+
| 1 | user01 | 2018-01-14 14:08:48 |
| 2 | user02 | NULL |
| 3 | user03 | NULL |
| 4 | user04 | NULL |
| 5 | user05 | NULL |
| 6 | user06 | NULL |
| 7 | user07 | NULL |
| 8 | user08 | NULL |
| 9 | user09 | NULL |
| 10 | user10 | NULL |
+----+--------+---------------------+
問題なく最終ログイン日時が更新されました。
まとめ
以上で作業は完了となります。
Laravel の認証機能回りは、トレイトの形で色々な処理が実装されていますが、オーバーライドすればコントローラ内で認証過程の処理を実装する事が出来るので覚えておくと便利です。
また、vendor配下のファイルに直接手を入れる場合、Github などでソース管理を行っていると除外されていてコミットされないので注意が必要です。そのためにも、組み込み機能のソースには手を付けず、出来るだけ組み込まれている処理についてはオーバーライドで実装するようにしましょう。