Now, let's discuss Middleware and authorization. We will create a special users.is_admin column in the DB and restrict non-admin users from access to manage categories.
Route Groups and Middleware
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 redirects to an error page. For example, if someone wants to visit the /dashboard URL protected with auth Middleware, they will automatically be redirected to the login page.
Now, look at our current Routes file.
routes/web.php:
use App\Http\Controllers\CategoryController;use App\Http\Controllers\ProfileController;use Illuminate\Support\Facades\Route; 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::resource('categories', CategoryController::class); require __DIR__.'/auth.php';
I see two problems here:
- Middleware
authis used for both the Dashboard and the Profile group: can we somehow combine them? - The Categories resource doesn't use
auth, so it's available to every public user without logging in.
In the routes/web.php, we already have one Route group for the profile links. We can move both Dashboard and Categories 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'); })->middleware(['verified'])->name('dashboard'); Route::resource('categories', CategoryController::class); }); require __DIR__.'/auth.php'; Route::resource('categories', CategoryController::class);
If you try to access any of these routes as a guest, you should be redirected to the login page.
As you can see, we moved the Dashboard inside the auth Middleware group. Still, we can additionally assign more Middleware checks like verified (is user's email verified) to any Route within a group.
Here's the GitHub commit for this change.
Admin User: DB Structure
Let's add a new column to the users table to define whether the user is an admin.
php artisan make:migration add_is_admin_to_users_table
Here's what's inside our Migration:
public function up(): void{ Schema::table('users', function (Blueprint $table) { $table->boolean('is_admin')->default(false); });}
If we run php artisan migrate, we will have this column:

Categories: Only for Admin Users
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 your application needs and abort the request if needed.
In our created Middleware, if the is_admin field in the User table is false, we must abort with the "403 Forbidden" status. Here's the syntax.
app/Http/Middleware/IsAdminMiddleware.php:
namespace App\Http\Middleware; use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response; class IsAdminMiddleware{ public function handle(Request $request, Closure $next): Response { if (! auth()->check() || ! auth()->user()->is_admin) { abort(403); } return $next($request); }}
The currently authenticated user can be obtained using Laravel helpers auth()->user() and then call the field liks is_admin.
Also, there's auth()->check(), which returns true if the user is logged in.
Next, we can use the Middleware in our Routes by providing the class name directly.
routes/web.php:
use App\Http\Middleware\IsAdminMiddleware; // ... Route::middleware('auth')->group(function () { Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); // ... Route::resource('categories', CategoryController::class) ->middleware(IsAdminMiddleware::class); });
If you try to access categories Routes with a user who isn't an admin, you will see a forbidden error message:

So, this is how you use Route Groups and Middlewares in Laravel to restrict access to some routes.
Here's the GitHub commit for this lesson.
In the next lesson, we will practice to create another CRUD, managing Posts.
No comments or questions yet...