Search code examples
laravelroutesmiddleware

Laravel group multiple Middleware


In my application I have three user roles:

  1. user
  2. editor
  3. admin

When editor logs into the admin section, some of the sections are hidden (users manage, system information etc.) and of course, the admin can see everything.

So, for this purpose I've created two middleware: Admin and Editor. This is the code.

Admin middleware.

<?php

namespace App\Http\Middleware;
use Illuminate\Support\Facades\Auth;

use Closure;

class Admin
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(Auth::check()) {
          if(Auth::user()->role_id == 3) {
            return $next($request);
          }
        }

        return redirect('/');

    }
}

Editor middleware:

<?php

namespace App\Http\Middleware;
use Illuminate\Support\Facades\Auth;

use Closure;

class Editor
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(Auth::check()) {
          if(Auth::user()->role_id == 2) {
            return $next($request);
          }
        }

        return redirect('/');

    }
}

Here's the part of the Kernel:

protected $routeMiddleware = [

'admin' => \App\Http\Middleware\Admin::class,
'editor' => \App\Http\Middleware\Editor::class,

];

Now I'm trying to build the routes that will be available to those user roles. If I do it only for the admin or the editor, it works fine, but when I combine them, the one user can login and the other cannot.

Here's the code only for the admin and it works fine.

Route::middleware('admin')->group(function(){

  Route::get('/admin', 'PagesController@adminIndex');
  Route::resource('/admin/pages', 'PagesController');
  Route::resource('/admin/news', 'NewsController');
  Route::resource('/admin/users', 'UsersController');
  ...
});

I've tried to combine them with this code, but it's not working (cannot login into the admin section at all):

Route::middleware(['admin', 'editor'])->group(function(){

  Route::get('/admin', 'PagesController@adminIndex');
  Route::resource('/admin/pages', 'PagesController');
  Route::resource('/admin/news', 'NewsController');
  Route::resource('/admin/users', 'UsersController');
  ...
});

How can I solve this problem?

P.S. Later I want to build a logic for the User role too, so there's must a way to combine the routes.


Solution

  • You can solve the problem with help of Middleware Parameters and instead of several middlewares for each role use only one universal middleware with roles as parameters.

    For example:

    protected $routeMiddleware = [
       'checkRole' => \App\Http\Middleware\CheckRole::class,
    ];
    

    Middleware:

    <?php
    
    namespace App\Http\Middleware;
    use Illuminate\Support\Facades\Auth;
    
    use Closure;
    
    class CheckRole
    {
        public function handle($request, Closure $next, ...$roles)
        {
            $roleIds = ['user' => 1, 'editor' => 2, 'admin' => 3];
            $allowedRoleIds = [];
            foreach ($roles as $role)
            {
               if(isset($roleIds[$role]))
               {
                   $allowedRoleIds[] = $roleIds[$role];
               }
            }
            $allowedRoleIds = array_unique($allowedRoleIds); 
    
            if(Auth::check()) {
              if(in_array(Auth::user()->role_id, $allowedRoleIds)) {
                return $next($request);
              }
            }
    
            return redirect('/');
    
        }
    }
    

    Routes:

    Route::middleware(['checkRole:admin,editor'])->group(function(){
      //Your routes  
    });