pijler/user-devices
Composer 安装命令:
composer require pijler/user-devices
包简介
This package provides support for managing user devices.
README 文档
README
This package provides support for managing user devices in Laravel. Track login devices, detect new logins, send notifications, and allow users to block suspicious devices—useful for security monitoring, session management, and multi-device applications.
🧩 Features
- ✅ Device tracking: Automatic tracking of IP address, user agent, location, and session ID
- ✅ New login detection: Identifies first-time logins from new devices
- ✅ Email notifications: Sends alerts when a new device logs in, on login attempts, and on failed logins
- ✅ Configurable events: Enable or disable listeners per auth event (authenticated, attempting, failed)
- ✅ Location from IP: Optional geolocation via callback
- ✅ Block device: Signed links to block suspicious devices in all notification types (invalidates session when blocked)
- ✅ Integrated middleware: Protect routes from blocked devices
- ✅ Block login check: Prevent blocked devices from attempting login via
isCurrentDeviceBlocked() - ✅ Model trait: Simple Eloquent integration
- ✅ Flexible configuration: Custom models and callbacks
📦 Installation
You can install the package via Composer:
composer require pijler/user-devices
🗄️ Publishing
Publish the package config (optional):
php artisan vendor:publish --tag=user-devices-config
Publish the package migrations:
php artisan vendor:publish --tag=user-devices-migrations
Run the migrations:
php artisan migrate
⚙️ Configuration
Config File
// config/user-devices.php return [ 'events' => [ 'failed' => true, // Track failures, notify when new device 'attempting' => false, // Track attempts, notify when new device 'authenticated' => true, // Save device + send new login notification ], 'credential_key' => 'email', // Key to find user from credentials (attempting/failed) ];
DeviceCreator
The package works out-of-the-box, but you can customize the behavior:
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\URL; use UserDevices\DeviceCreator; use UserDevices\Notifications\AuthenticatedLoginNotification; class AppServiceProvider extends ServiceProvider { public function boot(): void { // Use custom user model DeviceCreator::useUserModel(CustomUser::class); // Use custom user device model DeviceCreator::useUserDeviceModel(CustomUserDevice::class); // Customize user agent generation DeviceCreator::userAgentUsing(fn ($userAgent) => substr($userAgent, 0, 255)); // Control when to send notifications (e.g. disable in local/staging) DeviceCreator::shouldSendNotificationUsing(function ($user, $device) { return ! app()->environment('local'); }); // Resolve location from IP (optional) DeviceCreator::resolveLocationUsing(function (string $ip) { $geo = geoip($ip); return $geo->city ? "{$geo->city}, {$geo->country}" : $geo->country; }); // Customize the notification email AuthenticatedLoginNotification::toMailUsing(function ($notifiable, $device) { $expire = Config::get('auth.verification.expire', 60); $blockUrl = URL::temporarySignedRoute( name: 'user-devices.block', expiration: Carbon::now()->addMinutes($expire), parameters: [ 'id' => $device->getKey(), 'hash' => sha1($device->getKey()), ], ); return (new MailMessage) ->subject('New device detected') ->line('We detected a new login to your account.') ->action('Block device', $blockUrl); }); // Customize the block device URL AuthenticatedLoginNotification::createBlockUrlUsing(function ($device) { return URL::temporarySignedRoute( name: 'your-custom-route-name', expiration: Carbon::now()->addMinutes(120), parameters: [ 'id' => $device->getKey(), 'hash' => sha1($device->getKey()), ], ); }); } }
The block link expiration uses auth.verification.expire (default 60 minutes), same as Laravel's email verification.
🧠 Usage
1. Using the HasUserDevices Trait
Add the HasUserDevices trait to your User model. Your User model must also use the Notifiable trait for notifications:
use Illuminate\Notifications\Notifiable; use UserDevices\Traits\HasUserDevices; class User extends Authenticatable { use HasUserDevices; use Notifiable; }
2. Saving User Devices
The package automatically saves user devices when auth events fire. No manual setup required—just add the HasUserDevices trait to your User model.
- Authenticated: Saves/updates device (IP, user agent, location, session ID). Sends notification only on first login from that device.
- Attempting: Same as above. Finds user by email in credentials (when
events.attemptingis enabled). - Failed: Same as above. Uses user from event or resolves from credentials (when
events.failedis enabled).
All three events use firstOrNew by IP + user agent, so the same device is updated across requests.
To skip saving the device entirely for a request (e.g. in middleware or controller before authentication):
use UserDevices\DeviceCreator; DeviceCreator::ignoreListener();
To ignore only the new login notification (device is still saved, but no email is sent):
DeviceCreator::ignoreNotification();
To control notifications globally (e.g. disable in local/staging, or custom logic per user/device):
DeviceCreator::shouldSendNotificationUsing(fn () => false); DeviceCreator::shouldSendNotificationUsing(fn ($user, $device) => ! $user->isAdmin()); DeviceCreator::shouldSendNotificationUsing(fn ($user, $device) => app()->environment('production'));
3. Block Device Route
When a user receives the new login notification email, they can click a link to block the device. Register a route that handles this request. Blocking invalidates the device's session when using session-based auth. The route must be signed and named user-devices.block:
use UserDevices\Http\Requests\BlockDeviceRequest; Route::get('/devices/block/{id}/{hash}', function (BlockDeviceRequest $request) { $request->fulfill(); return redirect()->route('home')->with('message', 'Device blocked successfully.'); })->middleware(['signed', 'throttle:6,1'])->name('user-devices.block');
You can use any path you prefer as long as the route is named user-devices.block and includes the {id} and {hash} parameters. All three notification types (Authenticated, Attempting, Failed) include a block link in the email.
4. Check Blocked Device Before Login
To prevent blocked devices from attempting login, call isCurrentDeviceBlocked() after resolving the user (e.g. by email) and before validating the password. In a custom login controller or FormRequest:
// In your login logic, after resolving the user from credentials (e.g. email) $user = User::where('email', $request->email)->first(); if ($user && $user->isCurrentDeviceBlocked()) { return response()->json(['message' => 'This device has been blocked.'], 423); } // Proceed with login attempt...
Or in a FormRequest's authorize or custom validation:
public function authorize(): bool { $user = User::where('email', $this->email)->first(); return ! ($user && $user->isCurrentDeviceBlocked()); }
5. Using the Middleware
The package includes middleware to block requests from devices the user has blocked:
Route::middleware(['auth', 'check.device'])->group(function () { Route::get('/dashboard', [DashboardController::class, 'index']); });
When a blocked device tries to access a protected route, the middleware returns 423 Locked.
6. Working with the UserDevice Model
use UserDevices\Models\UserDevice; // Get user's devices $devices = $user->userDevices; // Block a device (invalidates session if session_id is set) $device = UserDevice::find($id); $device->block(); // Unblock a device $device->unblock(); // Block by ID (static) UserDevice::markAsBlocked($id); // Unblock by ID (static) UserDevice::markAsUnblocked($id);
7. Sending Notifications Manually
$user->sendFailedLoginNotification($device); $user->sendAttemptingLoginNotification($device); $user->sendAuthenticatedLoginNotification($device);
8. Customizing Attempting & Failed Login Notifications
use UserDevices\Notifications\AttemptingLoginNotification; use UserDevices\Notifications\FailedLoginNotification; AttemptingLoginNotification::toMailUsing(fn ($notifiable, $device) => (new MailMessage) ->subject('Login attempt')->line("IP: {$device->ip_address}")); AttemptingLoginNotification::createBlockUrlUsing(fn ($device) => URL::temporarySignedRoute(/* ... */)); FailedLoginNotification::toMailUsing(fn ($notifiable, $device) => (new MailMessage) ->subject('Failed login')->line("IP: {$device->ip_address}")); FailedLoginNotification::createBlockUrlUsing(fn ($device) => URL::temporarySignedRoute(/* ... */));
🧩 API Reference
DeviceCreator
// Configuration DeviceCreator::useUserModel(string $model): void DeviceCreator::useUserDeviceModel(string $model): void DeviceCreator::userAgentUsing(Closure $callback): void DeviceCreator::resolveLocationUsing(Closure $callback): void // (string $ip) => ?string DeviceCreator::shouldSendNotificationUsing(Closure $callback): void // (user, device) => bool // Request context (call before authentication) DeviceCreator::ignoreListener(): void // Skip saving the device for the current request DeviceCreator::ignoreNotification(): void // Skip the new login notification for the current request
UserDevice Model
// Relationships $device->user(): BelongsTo // Actions $device->block(): void // Also invalidates session when session_id is set $device->unblock(): void // Static methods UserDevice::markAsBlocked(mixed $id): void UserDevice::markAsUnblocked(mixed $id): void
HasUserDevices Trait
// Methods available on model $model->userDevices(): HasMany $model->isCurrentDeviceBlocked(): bool // Check if current request's device is blocked (use before login) $model->sendFailedLoginNotification(UserDevice $device): void $model->sendAttemptingLoginNotification(UserDevice $device): void $model->sendAuthenticatedLoginNotification(UserDevice $device): void
AuthenticatedLoginNotification
AuthenticatedLoginNotification::toMailUsing(Closure $callback): void AuthenticatedLoginNotification::createBlockUrlUsing(Closure $callback): void
AttemptingLoginNotification & FailedLoginNotification
AttemptingLoginNotification::toMailUsing(Closure $callback): void AttemptingLoginNotification::createBlockUrlUsing(Closure $callback): void FailedLoginNotification::toMailUsing(Closure $callback): void FailedLoginNotification::createBlockUrlUsing(Closure $callback): void
BlockDeviceRequest
$request->fulfill(): void $request->getDevice(): ?UserDevice
📝 License
Open-source under the MIT license.
🚀 Thanks!
pijler/user-devices 适用场景与选型建议
pijler/user-devices 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 747 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 01 月 31 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「package」 「laravel」 「Devices」 「user-devices」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 pijler/user-devices 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 pijler/user-devices 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 pijler/user-devices 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.
Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.
Simple ASCII output of array data
Agent is a PHP/Laravel package for detecting devices/bots via the http request.
FluxUI front-end for managing devices and sessions using diego-ninja/laravel-devices
统计信息
- 总下载量: 747
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 6
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-01-31