Courses

[FREE] Laravel 11 For Beginners: Your First Project

Middleware and Route Groups

Now, let's talk about Middleware and authentication. We created an administrator user, so let's assign access to that user to manage categories.


We have already seen the auth Middleware, which allows only logged-in users to access Routes. The auth is one of the Middlewares offered by the Laravel framework.

Middleware runs some checks before Routes, and if it returns false, it shows errors or redirect to some error page. For example, if someone wants to visit the /dashboard URL, protected with auth Middleware, they will automatically get redirected to the login page.

Laravel has some default Middlewares. You can always check them in the official documentation.

The web Middleware Group
Illuminate\Cookie\Middleware\EncryptCookies
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse
Illuminate\Session\Middleware\StartSession
Illuminate\View\Middleware\ShareErrorsFromSession
Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
Illuminate\Routing\Middleware\SubstituteBindings

We should assign our category resource route to the auth Middleware. We could add the middleware() method to the Route and provide the Middleware, or if the Route has multiple Middlewares, they can be provided as an array. But let's use Route group instead.

In the routes/web.php, we already have one Route group for the profile links. We can move all the Routes to that group. The syntax to have grouped Routes is to use what you need on a Route facade like middleware, prefix, etc., and then have a group method with a closure and add all the Routes in the closure.

routes/web.php:

Route::get('/', function () {
return view('welcome');
});
 
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
 
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
 
Route::get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
 
Route::resource('categories', \App\Http\Controllers\CategoryController::class);
});
 
require __DIR__.'/auth.php';
 
Route::resource('categories', \App\Http\Controllers\CategoryController::class);

If you try to access any of these routes as a guest, you should be redirected to the login page.


Now, let's create our custom Middleware to check if a user is an admin. Middleware can be created using an artisan command.

php artisan make:middleware IsAdminMiddleware

Middlewares are created in the app/Http/Middleware folder. The default structure of the Middleware is the handle(), which returns the next request. Before the return, you can add conditions that your application needs and abort the next request if needed.

In our created Middleware, if the is_admin field in the User table is false, we must abort with the forbidden status. The currently authenticated user can be obtained using Laravel helpers auth()->user() and then call the needed field.

app/Http/Middleware/IsAdminMiddleware.php:

class IsAdminMiddleware
{
public function handle(Request $request, Closure $next): Response
{
if (! auth()->user()->is_admin) {
abort(403);
}
 
return $next($request);
}
}

Next, we must register our Middleware to use it as an alias. Middleware is registered in the bootstrap/app.php file.

bootstrap/app.php:

return Application::configure(basePath: dirname(__DIR__))
->withProviders()
->withRouting(
web: __DIR__.'/../routes/web.php',
// api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
// channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'is_admin' => \App\Http\Middleware\IsAdminMiddleware::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();

Now, we can use is_admin Middleware in our application. Because we need to restrict access only to category routes, Middleware needs to be used on that route instead of a group.

routes/web.php:

Route::get('/', function () {
return view('welcome');
});
 
Route::middleware('auth')->group(function () {
// ...
 
Route::resource('categories', \App\Http\Controllers\CategoryController::class)->middleware('is_admin');
});
 
require __DIR__.'/auth.php';

Another option to apply Middleware instead of using aliases pass the Middleware class.

routes/web.php:

Route::get('/', function () {
return view('welcome');
});
 
Route::middleware('auth')->group(function () {
// ...
 
Route::resource('categories', \App\Http\Controllers\CategoryController::class)->middleware(\App\Http\Middleware\IsAdminMiddleware::class);
});
 
require __DIR__.'/auth.php';

If you try to access categories Routes with a user who isn't an admin, you will see a forbidden error message.

avatar

After add the middleware IsAdminMiddleware, then it show errors: Attempt to read property "is_admin" on null

avatar

is_admin value cannot be null. It should be true (1) or false (0)

avatar

Good evening, if I put the Part

if (! auth()->user()->is_admin) { abort(403); }

in the IsAdminMiddleware.php I get the error "undefined method user" . Do I have to add something in the "use" part at the top ?

But it works, just vs.code shows an error in the file.

👍 1
avatar

vscode does not understand. maybe getting user from the request vscode wouldn't complain. $request->user()

avatar

Oh this leads to a great Server Error. Anyhow its an Intelliphense Error (i saw it on google). Its not nice, because the whole strucutre is red in vs code is red and it shows an error. But the code works fine :-) So its ok for me I think.

But thanks a lot !

avatar

"If you try to access any of these routes as a guest, you should be redirected to the login page."

I can confirm this part. But I don't get where in the Laravel Framework code this bit is handle.

What if I want to redirect it to a different route, (probably not I good idea, but I just want to play around) how can I do that?

Thanks in advance.

avatar

This code is handled using Middleware. Specifically this one:

vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php

And you can always change where it redirects:

https://laraveldaily.com/search?q=login%20redirect

avatar

Thanks @Modestas.