Search code examples
phplaravelmiddlewarelaravel-8laravel-middleware

Laravel 8: Custom Middleware Does Not Seem To Be Working


I'm using Laravel 8 for my project and in this project and I have created a custom Middleware called Admin that goes like this:

public function handle(Request $request, Closure $next)
{
    if (Auth::check()) {
        if (Auth::user()->isAdmin()) {
            return $next($request);
        }
    }

    return redirect('/');
}

And I tried applying it like this:

Route::group(['middleware' => 'admin'], function() {
    Route::resource('admin/users', App\Http\Controllers\Admin\AdminUserController::class);
});

And on Kernel.php:

'admin' => \App\Http\Middleware\Admin::class

So I called the isAdmin() at User Model which simply checks if the role of the user is correct or not:

public function roles()
{
    return $this->belongsToMany(Role::class);
}

public function isAdmin()
{
    foreach ($this->roles as $role) {
        if ($role->name == 'Manual User') {
            return true;
        }
    }

    return false;
}

Currently, I have these two roles:

enter image description here

And the user, that I want to log in, is set to 6 and has the role id of 1 which Manual User:

enter image description here

But now the problem is, when I go to /admin/users uri, it does not redirect me to ('/') uri and shows me /admin/users page!

So what is going wrong here? How can I fix this issue?

Note that the relationship between roles and users which is Many To Many works fine and there is no need to mention them.


Solution

  • I tried this locally with a very similar setup and had no problem. I took the liberty of changing/simplifying some things.

    These are the steps I took.

    1. Middleware

    1.1. Create Admin middleware.

    Done by running the php artisan make:middleware Admin command.

    1.2. Fill out the middleware.

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    
    class Admin
    {
        /**
         * Passes if authenticated user is an admin.
         *
         * @see App\Models\User::isAdmin()
         */
        public function handle(Request $request, Closure $next)
        {
            if (Auth::user()->isAdmin()) {
                return $next($request);
            }
    
            return redirect('/');
        }
    }
    

    Here is my first change: I don't do the Auth::check(). There's another middleware for that.

    1.3 Add new entry to $middlewareGroups in App\Http\Kernel.php.

        protected $middlewareGroups = [
            'web' => [...],
    
            'api' => [...],
    
            // check if user is authenticated, then check if it's an admin
            'admin' => [
                'auth',
                \App\Http\Middleware\Admin::class
            ],
        ];
    
        protected $routeMiddleware = [
            'auth' => \App\Http\Middleware\Authenticate::class,
            ...
        ];
    

    2. Route

    Add a route that uses the middleware created above.

    Route::middleware('admin')->group(function () {
        Route::get('test', function () { return "User is authenticated and is an admin."; });
    });
    

    Also, optionally you could simplify your isAdmin() method.

    public function isAdmin()
    {
        return $this->roles->contains('name', 'Manual User');
    }
    

    This, for me, had the desired results. Are you sure you edited your App\Http\Kernel.php file correctly?