Laravel — P57: Controller Middleware

Secure actions with controller-level middleware

Where do you add your middleware? We looked at adding it to our routes file, but we also added it to our Kernel.php in a previous example. Now we’re looking to add it to our Controller? Won’t this get confusing?

If you need to freshen up on the middleware in routes topic, check out the article that I wrote on it when we looked at route groups.

https://medium.com/geekculture/laravel-p54-route-groups-middleware-and-controllers-f41804f40d31

We looked at adding it in our Kernel file when we were implementing the throttle:web middleware.

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    // ...

    /**
     * The application's route middleware groups.
     *
     * @var array<string, array<int, class-string|string>>
     */
    protected $middlewareGroups = [
        'web' => [
           'throttle:web',
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

    // ...
}

In our route, it was simple to see.

Route::middleware(['throttle:web', 'auth'])->group(function () {
    Route::get('/throttle-test-3', function() {
        return "Throttle Test 3";
    });

    Route::get('/throttle-test-4', function() {
        return "Throttle Test 4";
    });
});

Before we get to the controller, is there any other place that we can add middleware? There is: the RouteServiceProvider.

<?php

namespace App\Providers;

use App\Models\User;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * The path to the "home" route for your application.
     *
     * Typically, users are redirected here after authentication.
     *
     * @var string
     */
    public const HOME = '/home';

    /**
     * Define your route model bindings, pattern filters, and other route configuration.
     *
     * @return void
     */
    public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::middleware('api')
                ->prefix('api')
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->group(base_path('routes/web.php'));
        });

        Route::bind('verifiedUser', function($value) {
            return User::where('id', $value)
                ->where('email_verified_at', '!=', null)
                ->firstOrFail();
        });
    }

    // ...
}

You can see that the api and web middleware are applied to specific route files.

So, how do we apply it inside of the controller. You’ll simply add the middleware in the constructor. Let’s create a new controller called MiddlewareTestController.

# php artisan make:controller MiddlewareTestController

   INFO  Controller [app/Http/Controllers/MiddlewareTestController.php] created successfully.  

#

Next, we’ll create a route that points to an index method inside of it.

use App\Http\Controllers\MiddlewareTestController;

Route::get('/controller-middleware-test', [MiddlewareTestController::class, 'index']);

Next, let’s create our index method and a few other methods that may be used later on, such as the store and create methods.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MiddlewareTestController extends Controller
{
    public function index()
    {
        return "Middleware Controller";
    }

    public function store(Request $request)
    {
        return "Store some form datar";
    }

    public function create()
    {
        return "Return Form";
    }
}

Finally, we can add our middleware. It simply goes inside of the constructor. The example that we’ll use is for the auth middleware. I believe this will help illustrate why we might add middleware to a controller vs a route.

To apply the auth middleware to all of the methods inside of the controller, we simply add $this->middleware(‘auth’) inside the constructor.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MiddlewareTestController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function index()
    {
        return "Middleware Controller";
    }

    public function store(Request $request)
    {
        return "Store some form datar";
    }

    public function create()
    {
        return "Return Form";
    }
}

However, in some cases, we may want to not restrict the user on index.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MiddlewareTestController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth')->except('index');
    }

    // ...
}

This time, we apply the middleware to all methods except the index method.

We could also only restrict the store method where the user must be logged in to actually submit a form.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MiddlewareTestController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth')->only('store');
    }

    // ...
}

We can restrict the user to the create and store method. This is the same thing as what we just did with the except('index') piece of code, only worded differently.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MiddlewareTestController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth')->only(['create', 'store']);
    }

    // ...
}

This might be more visually appealing to you, however, it can definitely be done in the route file. It does get down to preference most of the time. Just be consistent. To implement it in a route file, you would simply add the auth middleware to the routes that you want to affect.

use App\Http\Controllers\MiddlewareTestController;

Route::get('/controller-middleware-test', [MiddlewareTestController::class, 'index']);

Route::middleware(['auth'])->group(function () {
    Route::get('/controller-middleware-test', [MiddlewareTestController::class, 'store']);
    Route::get('/controller-middleware-test', [MiddlewareTestController::class, 'edit']);
});

https://github.com/dinocajic/youtube-laravel

Laravel Series

Continue your Laravel Learning.

Laravel — P56: Dependency Injection in Controllers

Inject services, unclutter your controllers

Laravel – P56: Dependency Injection In Controllers

In part 56 of our Laravel series, deep-dive into leveraging the framework’s service container directly inside controllers. See how constructor and method injection reduce boilerplate, improve testability, and keep your business logic sharply focused.

Laravel — P57: Controller Middleware

Secure actions with controller-level middleware

Laravel – P57: Middleware In Controllers

In part 57 of our Laravel series, discover how to register and apply middleware directly within controllers. Learn to secure sensitive actions, share common logic, and override route defaults for concise, maintainable code.

 

Laravel — P58: Resource Controllers

Simplify CRUD with resource controllers

Laravel – P58: Resource Controllers

In part 58 of our Laravel fundamentals series, learn how resource controllers streamline CRUD operations. Explore generator commands, automatic RESTful routes, customizing actions, and keeping your controllers clean and maintainable. (233 characters)

 

Leave a Reply