makaveli / laravel-login-history
Advanced Login History for Laravel
Requires
- php: ^8.2
- laravel/framework: ^10.10|^11.0|^12.0
- makaveli/laravel-logger: ^1.1.4
- makaveli/laravel-query-builder: ^1.1.4
README
🌍 Languages
- 🇺🇸 English (default)
- 🇷🇺 Русская версия
Table of Contents
- Introduction
- Requirements
- Installation
- Configuration
- Core Components
- Database Schema
- Quick Start
- Integration with BaseRepository
- Extending the Package
- Recommendations
- Useful Links
Introduction
makaveli/laravel-login-history is a Laravel package that provides advanced logging of user authentication events. It records the user ID and a fingerprint – structured data about the session or device used to log in. The package supports asynchronous logging via queues, flexible filtering, pagination, and integrates seamlessly with makaveli/laravel-core and makaveli/laravel-query-builder.
Key features:
- Recording login history with user binding and arbitrary JSON fingerprint.
- Asynchronous logging through Laravel queues.
- Filtering and pagination of login history data.
- Console commands to generate test data and run migrations.
- Configurable support for roles and organizations (optional).
- Easy adaptation via filter transformers.
Requirements
- PHP 8.2 or higher
- Laravel 10.10, 11.0, or 12.0
- makaveli/laravel-query-builder (v1.1.4)
- makaveli/laravel-logger (v1.1.4)
Installation
-
Install the package via Composer:
composer require makaveli/laravel-login-history
-
(Optional) Publish the configuration file to customize settings:
php artisan vendor:publish --tag=login-history-config
This will copy the configuration file to
config/login-history.php. -
Run the package migrations to create the history table:
php artisan migrate:login-history
This creates the
users.user_login_historiestable.
Configuration
The file config/login-history.php allows you to configure the following parameters:
| Parameter | Description | Default |
|---|---|---|
user_model |
User model class | App\Models\User::class |
search_filter_fields |
Model fields to search via the search parameter |
['name', 'patronymic', 'family_name', 'phone', 'email'] |
with_role |
Whether the user model has a role relationship (affects role filtering) | true |
with_organization |
Whether the role model has an organization_id field (affects organization filtering) |
true |
advanced_filters |
Callback for adding custom filters | null |
user_login_history |
Number of test records generated by the seeder | 100 |
transformers |
Array of functions to transform filter parameters | [] |
user_resource |
Resource class for formatting user data | [\App\Modules\Base\Resources\UserShortResource::class, 'once'] |
Example configuration:
return [ 'user_model' => App\Modules\Base\Models\User::class, 'search_filter_fields' => ['name', 'patronymic', 'family_name', 'phone', 'email'], 'with_role' => true, 'advanced_filters' => function (\LoginHistory\Filters\UserLoginHistoryFilters $self) { $self->applyInteger('user_id'); }, 'with_organization' => true, 'user_login_history' => env('USER_LOGIN_HISTORY_FACTORY', 100), 'transformers' => [ 'role_id' => [\App\Modules\Role\Helpers\TransformRoleFilter::class, 'getRealRoleIdFromListRequest'], 'user_id' => [\App\Modules\User\Helpers\TransformUserFilter::class, 'getRealUserIdFromListRequest'], 'organization_id' => [\App\Modules\Organization\Helpers\TransformOrganizationFilter::class, 'getRealOrganizationIdFromListRequest'], ], 'user_resource' => [\App\Modules\Base\Resources\UserShortResource::class, 'once'], ];
Core Components
LoginHistory Trait
The trait is added to the controller or any class where authentication occurs. It provides two methods:
writeLoginHistory(Request $request, ?Authenticatable $user = null): Synchronous history record.writeAsyncLoginHistory(Request $request, ?Authenticatable $user = null): Asynchronous record via queue.
use LoginHistory\Traits\LoginHistory; class AuthController extends Controller { use LoginHistory; public function login(Request $request) { // ... authentication ... $this->writeLoginHistory($request); // or $this->writeAsyncLoginHistory($request); } }
If no user is explicitly passed, the method uses auth()->user().
UserLoginHistoryActions
An action class that encapsulates the history writing logic. Can be used without the trait:
$actions = new UserLoginHistoryActions(); $actions->writeToHistory($user, $request);
UserLoginHistoryRepository
The repository for working with the UserLoginHistory model. It extends BaseRepository from makaveli/laravel-core and adds a getPaginatedList method that accepts a UserLoginHistoryListDTO and returns a paginated result.
use LoginHistory\Repositories\UserLoginHistoryRepository; use LoginHistory\DTO\UserLoginHistoryListDTO; $repository = new UserLoginHistoryRepository(); $dto = UserLoginHistoryListDTO::fromRequest($request); $paginator = $repository->getPaginatedList($dto);
UserLoginHistoryListDTO
A DTO for filtering the login history list. It extracts parameters from the request and applies transformers (if defined). Supported fields:
| Parameter | Type | Description |
|---|---|---|
dateFrom |
string | Start date (Y-m-d) |
dateTo |
string | End date (Y-m-d) |
roleId |
int | Filter by role ID (requires with_role = true) |
userId |
int | Filter by user ID |
organizationId |
int | Filter by organization ID (requires with_role = true and with_organization = true) |
search |
string | Search across fields defined in search_filter_fields |
Transformers (functions in the config) allow modifying these parameter values based on the current user’s permissions.
Filters
The package uses makaveli/laravel-query-builder. The UserLoginHistoryFilters class (extends BaseQueryBuilder) applies filters based on the DTO. You can extend it via the advanced_filters configuration parameter by providing a callback.
Example of adding a custom filter:
'advanced_filters' => function (\LoginHistory\Filters\UserLoginHistoryFilters $self) { $self->applyInteger('user_id'); },
Resources
UserLoginHistoryResource: Formats a single history record. By default it includesid,fingerprint,created_at, and the user formatted viauser_resource.PaginatedCollectionfromlaravel-query-builderis used for pagination.
Console Commands
| Command | Description |
|---|---|
php artisan seed:test-user-login-histories |
Creates test history records (count set by user_login_history) |
php artisan migrate:login-history |
Runs the package migrations |
Database Schema
The package creates the table users.user_login_histories:
| Column | Type | Description |
|---|---|---|
id |
bigint (PK) | Auto‑increment ID |
user_id |
bigint (FK) | ID of the user who logged in |
fingerprint |
jsonb | Arbitrary session/device data |
created_at |
timestamp | Login time |
updated_at |
timestamp | Last update time |
Quick Start
1. Configure the package (if needed)
Edit config/login-history.php – specify the correct user model, search fields, user resource, etc.
2. Add the trait to your authentication controller
use LoginHistory\Traits\LoginHistory; class AuthController extends Controller { use LoginHistory; public function login(Request $request) { // ... credentials check ... if (auth()->attempt($credentials)) { // Record history (synchronously) $this->writeLoginHistory($request); // or asynchronously: // $this->writeAsyncLoginHistory($request); return response()->json(['message' => 'Login successful']); } return response()->json(['message' => 'Invalid credentials'], 401); } }
3. Retrieve the history list in a controller
use LoginHistory\Repositories\UserLoginHistoryRepository; use LoginHistory\DTO\UserLoginHistoryListDTO; use QueryBuilder\Resources\PaginatedCollection; use LoginHistory\Resources\UserLoginHistoryResource; class UserLoginHistoryController extends Controller { public function index(Request $request) { $dto = UserLoginHistoryListDTO::fromRequest($request); $repository = new UserLoginHistoryRepository(); $paginator = $repository->getPaginatedList($dto); return new PaginatedCollection( $paginator, UserLoginHistoryResource::collection($paginator) ); } }
Integration with BaseRepository
UserLoginHistoryRepository already extends BaseRepository, so it can be used in a service provider or injected via the container. In a controller:
use LoginHistory\Repositories\UserLoginHistoryRepository; class UserLoginHistoryController extends Controller { public function __construct( private UserLoginHistoryRepository $repository ) {} public function index(Request $request) { $dto = UserLoginHistoryListDTO::fromRequest($request); $paginator = $this->repository->getPaginatedList($dto); return UserLoginHistoryResource::collection($paginator); } }
The getPaginatedList method automatically applies the filters defined in the DTO and configuration.
Extending the Package
You can customize the package by overriding:
- Model: Extend
LoginHistory\Models\UserLoginHistoryand bind your own model in a service provider if necessary. - Filters: Extend
UserLoginHistoryFiltersand override thelist()method, or useadvanced_filtersto add custom conditions. - DTO: Create your own DTO extending
UserLoginHistoryListDTOand overridefromRequest. - Resources: Create your own resource class and use it in
UserLoginHistoryResource(or directly in the controller). - Transformers: Define functions in the configuration to transform the
role_id,user_id, andorganization_idparameters.
Recommendations
- Always configure
user_modelaccording to your actual user model. - Use asynchronous logging (
writeAsyncLoginHistory) in production to avoid increasing response time. - Define transformers if you need to restrict data access based on the user’s role.
- Adjust the search fields in
search_filter_fieldsto match your user model. - When using roles and organizations, ensure your user model has the corresponding relationships.
- Add database indexes on
user_idandcreated_atfor faster queries.
Useful Links
- Package repository: https://github.com/Ma1kaveli/laravel-login-history
- Dependencies: