Search code examples
laravelroutesmiddleware

How can I use multiple middlewares on the same route name in Laravel 9?


I want my /dashboard page to be a different panel in 2 different user types. And return to home screen if not logged in. I created 2 middlewares to check if logged in user is "employer" or "employee". Whatever I do, I can't seem to make it work, it's been 2 days. I created middlewares and routes by following some very sketchy tutorials, it may hurt your eyes, be aware.

My route:

Route::get('/dashboard', function () {
    return view('welcome');
})->name('welcome');


Route::prefix('admin')->middleware([\App\Http\Middleware\isEmployer::class])->group( function () {
    Route::get("/dashboard", function (){
        return view("employer.dashboard");
    })->name("dashboard");
});


Route::prefix('store')->middleware([\App\Http\Middleware\isEmployee::class])->group( function(){
    Route::get("/dashboard", function (){
       return view("employee.dashboard");
    })->name("dashboard");
});

isEmployee middleware:

<?php

namespace App\Http\Middleware;

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

class isEmployee
{
    public function handle(Request $request, Closure $next)
    {
        if(Auth::user())
        {
            if (Auth::user()->role == "employee")
            {
                return $next($request);
            }
        }

        return response()->view('welcome');
    }
}

isEmployer middleware :

<?php

namespace App\Http\Middleware;

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

class isEmployer
{
    public function handle(Request $request, Closure $next)
    {
        if(Auth::user())
        {
            if (Auth::user()->role == "employer")
            {
                return $next($request);
            }
        }

        return response()->view('welcome');
    }
}

What I want to achieve is:

if not logged in : return welcome view

if logged in as employer : return employer.dashboard view

if logged in as employee : return employee.dashboard view


Solution

  • Let's start from some refactoring:

    1. Make your routes/web.php a bit more readable:

      Route::view('/dashboard', 'welcome')->name('welcome');
      
      Route::prefix('admin')->name('admin.')->middleware('role:employer')->group(function() {
          Route::view('/dashboard', 'employer.dashboard')->name("dashboard");
      });
      
      Route::prefix('store')->name('store.')->middleware('role:employee')->group(function() {
          Route::view('/dashboard', 'employee.dashboard')->name("dashboard");
      });
      
    2. Now let's create a middleware that will check not only for one role, but for any role you give as a parameter:

      <?php
      
      namespace App\Http\Middleware;
      
      use Closure;
      use Illuminate\Http\Request;
      use Illuminate\Support\Facades\Auth;
      
      class HasRole
      {
          public function handle(Request $request, Closure $next, string $role)
          {
              if (Auth::user()?->role != $role) {
                  return redirect()->route('welcome');
              }
      
              return $next($request);
          }
      }
      
    3. Now, create an alias in your app/Http/Kernel.php so you could use it like i wrote it in routes file role:<role_here>:

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

    Now for your question - how to use multiple middlewares for one route. It is simple:

    $route->middleware(['middleware1', 'middleware2']);
    

    You may attach them to groups or single routes:

    Route::prefix('some_group')->middleware(['middleware1', 'middleware2'])->group(function() {
        Route::view("some.view")->middleware('middleware3')->name("some.view");
    });
    

    You can read more info about Laravel's middlewares here, and understand what responsibility chain is (pattern which middleware implements) under the hood. Also take a look at SOLID principles, mainly at DRY one. Have a good day =)