Building an Admin Login System in Laravel with Livewire

Author

Kritim Yantra

May 12, 2025

Building an Admin Login System in Laravel with Livewire

In this comprehensive guide, we'll walk through creating a secure admin login system using Laravel and Livewire. This solution will include authentication, authorization, and a clean admin interface.

Table of Contents

  1. Introduction to Laravel and Livewire
  2. Project Setup
  3. Database Configuration
  4. Creating the Admin User Model
  5. Authentication Scaffolding
  6. Building the Login Component with Livewire
  7. Admin Dashboard
  8. Middleware for Admin Protection
  9. Logout Functionality
  10. Testing the System
  11. Conclusion

1. Introduction to Laravel and Livewire

Laravel is a powerful PHP framework that provides elegant syntax and tools for building modern web applications. It includes built-in features for authentication, routing, sessions, and caching.

Livewire is a full-stack framework for Laravel that makes building dynamic interfaces simple, without leaving the comfort of Laravel. It allows you to write front-end code directly in your Blade templates with reactive behavior.

Together, they provide an excellent stack for building interactive admin panels with real-time features.

2. Project Setup

First, let's create a new Laravel project:

composer create-project laravel/laravel admin-panel
cd admin-panel

Next, install Livewire:

composer require livewire/livewire

Add the Livewire directives to your layout file. Create resources/views/layouts/app.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Admin Panel</title>
    @livewireStyles
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100">
    {{ $slot }}
    
    @livewireScripts
</body>
</html>

3. Database Configuration

Set up your database in the .env file:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=admin_panel
DB_USERNAME=root
DB_PASSWORD=

Run the migrations:

php artisan migrate

4. Creating the Admin User Model

We'll use Laravel's built-in User model but extend it for admin functionality. First, let's modify the default migration:

// In database/migrations/..._create_users_table.php
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->boolean('is_admin')->default(false);
    $table->rememberToken();
    $table->timestamps();
});

Run the migration:

php artisan migrate:fresh

Update the User model (app/Models/User.php):

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
        'is_admin',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
        'is_admin' => 'boolean',
    ];

    public function isAdmin()
    {
        return $this->is_admin;
    }
}

5. Authentication Scaffolding

Install Laravel Breeze for authentication scaffolding:

composer require laravel/breeze --dev
php artisan breeze:install
php artisan migrate
npm install && npm run dev

This will set up the basic authentication views and routes.

6. Building the Login Component with Livewire

Create a new Livewire component for the admin login:

php artisan make:livewire Auth/AdminLogin

Update app/Http/Livewire/Auth/AdminLogin.php:

<?php

namespace App\Http\Livewire\Auth;

use Livewire\Component;
use Illuminate\Support\Facades\Auth;

class AdminLogin extends Component
{
    public $email;
    public $password;
    public $remember = false;
    public $error;

    protected $rules = [
        'email' => 'required|email',
        'password' => 'required',
    ];

    public function render()
    {
        return view('livewire.auth.admin-login')
            ->layout('layouts.app');
    }

    public function login()
    {
        $this->validate();

        $credentials = [
            'email' => $this->email,
            'password' => $this->password,
            'is_admin' => true,
        ];

        if (Auth::attempt($credentials, $this->remember)) {
            return redirect()->intended('/admin/dashboard');
        }

        $this->error = 'Invalid credentials or you are not an admin.';
    }
}

Create the view at resources/views/livewire/auth/admin-login.blade.php:

<div class="min-h-screen flex items-center justify-center">
    <div class="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
        <h1 class="text-2xl font-bold mb-6 text-center">Admin Login</h1>
        
        @if($error)
            <div class="mb-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded">
                {{ $error }}
            </div>
        @endif

        <form wire:submit.prevent="login">
            <div class="mb-4">
                <label for="email" class="block text-gray-700 mb-2">Email</label>
                <input 
                    type="email" 
                    id="email" 
                    wire:model="email" 
                    class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
                    autofocus
                >
                @error('email') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
            </div>

            <div class="mb-6">
                <label for="password" class="block text-gray-700 mb-2">Password</label>
                <input 
                    type="password" 
                    id="password" 
                    wire:model="password" 
                    class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
                >
                @error('password') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
            </div>

            <div class="mb-6 flex items-center">
                <input 
                    type="checkbox" 
                    id="remember" 
                    wire:model="remember" 
                    class="mr-2"
                >
                <label for="remember" class="text-gray-700">Remember me</label>
            </div>

            <button 
                type="submit" 
                class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-150"
            >
                Login
            </button>
        </form>
    </div>
</div>

7. Admin Dashboard

Create a Livewire component for the admin dashboard:

php artisan make:livewire Admin/Dashboard

Update app/Http/Livewire/Admin/Dashboard.php:

<?php

namespace App\Http\Livewire\Admin;

use Livewire\Component;

class Dashboard extends Component
{
    public function render()
    {
        return view('livewire.admin.dashboard')
            ->layout('layouts.app', ['title' => 'Admin Dashboard']);
    }
}

Create the view at resources/views/livewire/admin/dashboard.blade.php:

<div class="min-h-screen">
    <nav class="bg-white shadow">
        <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="flex justify-between h-16">
                <div class="flex">
                    <div class="flex-shrink-0 flex items-center">
                        <h1 class="text-xl font-bold text-gray-900">Admin Panel</h1>
                    </div>
                </div>
                <div class="flex items-center">
                    <form method="POST" action="{{ route('logout') }}">
                        @csrf
                        <button type="submit" class="text-gray-500 hover:text-gray-700 px-3 py-2 rounded-md text-sm font-medium">
                            Logout
                        </button>
                    </form>
                </div>
            </div>
        </div>
    </nav>

    <header class="bg-white shadow">
        <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
            <h2 class="text-xl font-semibold text-gray-900">
                Dashboard
            </h2>
        </div>
    </header>
    <main>
        <div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
            <div class="px-4 py-6 sm:px-0">
                <div class="border-4 border-dashed border-gray-200 rounded-lg h-96 p-4">
                    <p class="text-gray-500">Welcome to your admin dashboard!</p>
                    <p class="mt-4 text-gray-500">You're logged in as: {{ auth()->user()->email }}</p>
                </div>
            </div>
        </div>
    </main>
</div>

8. Middleware for Admin Protection

Create a middleware to protect admin routes:

php artisan make:middleware AdminMiddleware

Update app/Http/Middleware/AdminMiddleware.php:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class AdminMiddleware
{
    public function handle(Request $request, Closure $next)
    {
        if (!Auth::check() || !Auth::user()->isAdmin()) {
            return redirect('/admin/login')->with('error', 'You do not have admin access.');
        }

        return $next($request);
    }
}

Register the middleware in bootstrap/app.php:

<?php

use Illuminate\Foundation\Application;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php'
    )
    ->withMiddleware(function ($middleware) {
        $middleware->alias([
             'admin' => \App\Http\Middleware\AdminMiddleware::class,
        ]);
    })
    ->create();

9. Logout Functionality

Laravel Breeze already provides logout functionality, but let's ensure it works with our admin routes.

Update routes/web.php:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Livewire\Auth\AdminLogin;
use App\Http\Livewire\Admin\Dashboard;

Route::get('/admin/login', AdminLogin::class)->name('admin.login');
Route::get('/admin/dashboard', Dashboard::class)->name('admin.dashboard')->middleware('admin');

// Regular user routes
Route::get('/', function () {
    return view('welcome');
});

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');

require __DIR__.'/auth.php';

10. Testing the System

First, create an admin user. Create a seeder:

php artisan make:seeder AdminUserSeeder

Update database/seeders/AdminUserSeeder.php:

<?php

namespace Database\Seeders;

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class AdminUserSeeder extends Seeder
{
    public function run()
    {
        User::create([
            'name' => 'Admin User',
            'email' => 'admin@example.com',
            'password' => Hash::make('password'),
            'is_admin' => true,
        ]);
    }
}

Run the seeder:

php artisan db:seed --class=AdminUserSeeder

Now you can:

  1. Visit /admin/login
  2. Log in with admin@example.com and password
  3. You should be redirected to the admin dashboard
  4. Try accessing /admin/dashboard directly - it should redirect if not logged in
  5. Test the logout functionality

11. Conclusion

In this tutorial, we've built a complete admin login system using Laravel and Livewire. We've covered:

  • Setting up a Laravel project with Livewire
  • Creating an admin user model with special privileges
  • Building a Livewire login component
  • Creating a protected admin dashboard
  • Implementing middleware for route protection
  • Testing the authentication flow

Tags

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts