Wednesday, July 10, 2024

Laravel Custom Authentication

 1. Set Up Database

- Configure your .env file with your database credentials:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database
DB_USERNAME=your_username
DB_PASSWORD=your_password

- Run the migration to create the users table

php artisan migrate

2. Create Authentication Controller

Generate the Auth controller:

php artisan make:controller AuthController

3. Set Up Routes

Define routes for authentication in routes/web.php:

use App\Http\Controllers\AuthController;

Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login');
Route::post('/login', [AuthController::class, 'login']);
Route::get('/register', [AuthController::class, 'showRegistrationForm'])->name('register');
Route::post('/register', [AuthController::class, 'register']);
Route::post('/logout', [AuthController::class, 'logout'])->name('logout');
Route::get('/home', [AuthController::class, 'home'])->name('home')->middleware('auth');

4. Create Controller Methods

php artisan make:controller AuthController

Implement methods in AuthController.php:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function showLoginForm()
    {
        return view('auth.login');
    }

    public function login(Request $request)
    {
        $credentials = $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required'],
        ]);

        if (Auth::attempt($credentials)) {
            $request->session()->regenerate();

            return redirect()->intended('home');
        }

        throw ValidationException::withMessages([
            'email' => [trans('auth.failed')],
        ]);
    }

    public function showRegistrationForm()
    {
        return view('auth.register');
    }

    public function register(Request $request)
    {
        $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);

        User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        return redirect()->route('login');
    }

    public function logout(Request $request)
    {
        Auth::logout();

        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect('/');
    }

    public function home()
    {
        return view('home');
    }
}

5. Create Middleware

If not already present, create the Auth middleware:

php artisan make:middleware AuthMiddleware

In app/Http/Middleware/Authenticate.php, modify the redirectTo method:

protected function redirectTo($request)
{
    if (! $request->expectsJson()) {
        return route('login');
    }
}

6. Create Views

Create the views for login, registration, and home.

resources/views/auth/login.blade.php:

<form method="POST" action="{{ route('login') }}">
    @csrf
    <div>
        <label for="email">Email</label>
        <input type="email" id="email" name="email" required>
    </div>
    <div>
        <label for="password">Password</label>
        <input type="password" id="password" name="password" required>
    </div>
    <div>
        <button type="submit">Login</button>
    </div>
</form>

resources/views/auth/register.blade.php:

<form method="POST" action="{{ route('register') }}">
    @csrf
    <div>
        <label for="name">Name</label>
        <input type="text" id="name" name="name" required>
    </div>
    <div>
        <label for="email">Email</label>
        <input type="email" id="email" name="email" required>
    </div>
    <div>
        <label for="password">Password</label>
        <input type="password" id="password" name="password" required>
    </div>
    <div>
        <label for="password_confirmation">Confirm Password</label>
        <input type="password" id="password_confirmation" name="password_confirmation" required>
    </div>
    <div>
        <button type="submit">Register</button>
    </div>
</form>

resources/views/home.blade.php:

<h1>Welcome, {{ Auth::user()->name }}</h1>
<form method="POST" action="{{ route('logout') }}">
    @csrf
    <button type="submit">Logout</button>
</form>

7. Protect Routes with Middleware

Understanding Middleware:

  • Middleware acts as an interceptor for incoming HTTP requests.
  • It allows you to perform actions before a request reaches the intended controller or route.
  • In authentication, middleware checks if a user is logged in before allowing access to specific routes.

Using Built-in auth Middleware:

  • Laravel provides a built-in auth middleware that checks for user authentication.
  • You can assign this middleware to routes or groups of routes that require authentication.
Ensure the auth middleware is applied to routes that require authentication in app/Http/Kernel.php:

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    // other middlewares
];


Edit file routes/web.php

Route::middleware('auth')->group(function () {
    Route::get('/profile', function () {
        // This route is only accessible to authenticated users
        return view('profile');
    });

    Route::get('/dashboard', function () {
        // Another protected route
        return view('dashboard');
    });
});

// Alternatively, apply middleware to a single route
Route::get('/admin', [AdminController::class, 'index'])->middleware('auth');

Custom Authentication Middleware (Optional):

  • You can create custom middleware for more granular control over authentication.
  • Here's a basic example that checks for specific user roles:

Add a middleware file at app/Http/Middleware/RoleMiddleware.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class RoleMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request)  $next
     * @param  string  ...$roles
     * @return mixed
     */
    public function handle(Request $request, Closure $next, ...$roles)
    {
        if (! Auth::check() || ! $request->user()->hasRole($roles)) {
            return redirect('/login');
        }

        return $next($request);
    }
}

Register the middleware in app/Http/Kernel.php:

// app/Http/Kernel.php

protected $routeMiddleware = [
    // ... other middleware
    'role' => App\Http\Middleware\RoleMiddleware::class,
];


Use the custom middleware in your routes:

// routes/web.php

Route::get('/admin', [AdminController::class, 'index'])->middleware('role:admin');