lvlup-dev/laravel-user-is-admin
Installation:
composer require lvlup-dev/laravel-user-is-admin
php artisan migrate
The package auto-registers its migration (is_admin boolean column on users table) and middleware alias (admin).
First Use Case:
Protect an admin route in routes/web.php:
Route::middleware(['auth', 'admin'])->group(function () {
Route::get('/admin', [AdminController::class, 'dashboard']);
});
AuthenticationException (Laravel’s default).403 (AccessDeniedHttpException).Where to Look First:
app/Http/Middleware/EnsureUserIsAdmin.php (customize logic if needed).database/migrations/[timestamp]_add_is_admin_to_users_table.php (verify column type).tests/Feature/AdminMiddlewareTest.php for edge cases.Route Protection:
admin middleware alongside auth in route groups.
Route::middleware(['auth:sanctum', 'admin'])->group(function () {
// Admin-only routes
});
auth:api).
Route::middleware(['auth:api', 'admin'])->get('/admin/data', ...);
Dynamic Admin Checks:
is_admin from a custom column or API:
// app/Http/Middleware/EnsureUserIsAdmin.php
public function handle($request, Closure $next) {
if (!$request->user()->is_admin) {
abort(403, 'Custom admin message');
}
return $next($request);
}
Blade Directives:
@admin
<div>Admin Panel</div>
@endadmin
Register the directive in AppServiceProvider:
Blade::if('admin', fn () => auth()->check() && auth()->user()->is_admin);
Seeding Admins:
DatabaseSeeder.php:
User::create([
'name' => 'Admin User',
'email' => 'admin@example.com',
'password' => bcrypt('password'),
'is_admin' => true,
]);
Policy Integration:
// app/Policies/AdminPolicy.php
public function viewAny(User $user) {
return $user->is_admin;
}
actingAsAdmin() helper (if added) or mock the middleware:
$this->actingAs(User::factory()->is_admin(true)->create());
403 message in the middleware’s abort() call.is_admin rarely changes, cache the check in the User model:
public function getIsAdminAttribute() {
return cache()->remember("user-{$this->id}-is_admin", now()->addHours(1), fn () => $this->is_admin);
}
Migration Conflicts:
users table already exists, manually add the is_admin column:
ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT false;
php artisan migrate:fresh in a staging environment to test.Middleware Alias Overrides:
admin middleware alias. Check config/app.php under aliases.Case Sensitivity:
is_admin (snake_case). Avoid isAdmin in your code to match the DB column.Default Value:
DEFAULT false. New users will not be admins by default.API Tokens:
user() helper resolves correctly in middleware.dd(auth()->user()->is_admin); // Debug in middleware
\Log::debug('Non-admin access attempt by: ' . $request->user()->email);
php artisan package:discover if the admin alias isn’t recognized.Custom Logic: Override the middleware to check against a role or external service:
public function handle($request, Closure $next) {
if (!$this->isAdmin($request->user())) {
abort(403);
}
return $next($request);
}
protected function isAdmin(?User $user) {
return $user && $user->is_admin && $this->externalService->validateAdmin($user);
}
Dynamic Admin Roles: Use a trait to add dynamic admin checks:
// app/Traits/HasDynamicAdminRole.php
public function is_admin() {
return $this->is_admin || $this->email === 'dynamic@example.com';
}
Bulk Admin Updates: Add a command to update admins via email:
// app/Console/Commands/MakeAdmins.php
public function handle() {
User::whereIn('email', ['admin1@example.com', 'admin2@example.com'])
->update(['is_admin' => true]);
}
Soft Deletes:
If using SoftDeletes, ensure the middleware respects deleted users:
if ($request->user()->is_admin && !$request->user()->deleted_at) { ... }
is_admin when fetching users:
$users = User::with(['posts' => fn ($q) => $q->where('published', true)])
->get();
// No impact on `is_admin` (boolean column), but good practice.
How can I help you explore Laravel packages today?