Miljan Rakita
Miljan Rakita

Reputation: 1533

Laravel override group middleware

How to override group middleware? What i want to achieve is to add other throttle limit for register/login routes.

My current throttle is set in kernel.

'api' => [
        'throttle:40,1',
        'bindings',
    ],

I want to set new throttle limit for login/register routes.

This is how i did it.

Route::post('login', 'Api\UserController@login')->middleware('throttle:15,3')->name('user.login');
Route::post('register', 'Api\UserController@register')->middleware('throttle:15,3')->name('user.register');

When i run php artisan route:list it says that this middleware api,throttle:15,3 is applied to this route.

The problem is when i run login request, response header says

X-RateLimit-Limit       40
X-RateLimit-Remaining   38

So as far as i see my new middleware is not applied. But my throttle requests are counted twice. How can i apply different middleware for throttle on login/register routes and override the old one ?

Upvotes: 10

Views: 4686

Answers (4)

Zaid Bin Khalid
Zaid Bin Khalid

Reputation: 763

Remove the Throttle Middleware from the Global Group: In your app/Http/Kernel.php file, remove the Throttle Middleware from the global api group. The global group is applied to all routes by default.

Change this:

'api' => [
    'throttle:40,1',
    'bindings',
],

to this:

'api' => [
    'bindings',
],

Define a New Middleware Group: Create a new middleware group in your app/Http/Kernel.php file specifically for API throttling. You can give it a custom name like 'api.throttle'.

'api.throttle' => [
    'throttle:40,1', // The default throttle for most API routes
],

Apply the Custom Middleware Group to Most API Routes: Now, apply your new api.throttle middleware group to most of your API routes in your routes/api.php file. This will apply the default throttle to most routes.

Route::middleware(['api.throttle'])->group(function () {
    // Define your API routes here.
});

Override the Middleware on Login/Register Routes: For the login and register routes, you can override the api.throttle middleware with your custom throttle settings.

Route::post('login', 'Api\UserController@login')->middleware('throttle:15,3')->name('user.login');
Route::post('register', 'Api\UserController@register')->middleware('throttle:15,3')->name('user.register');

This is just an idea and the approach which I use most.

OR You can create a new call like below.

Define a new middleware group in the App\Http\Kernel.php file. For example, let's call it throttle-auth:

'throttle-auth' => 'throttle:15,3',

Apply like below.

Route::group(['middleware' => 'throttle-auth'], function () {
    Route::post('login', 'Api\UserController@login')->name('user.login');
    Route::post('register', 'Api\UserController@register')->name('user.register');
});

Upvotes: 0

clem
clem

Reputation: 424

As far as I know, the only way to override a group middleware is to disable it and then enable another one:

Route::withoutMiddleware(ThrottleRequests::class.':api')->group(function () {
    Route::middleware(ThrottleRequests::class.':custom')->group(function () {
        ///
    });
});

Let me know if there's a better way to do it. I'd like to clean this up.

Upvotes: 1

Jeffrey
Jeffrey

Reputation: 1804

Old topic, but its the first i found; time for an updated answer.

I've had this problem in the past as well. My solution back then was to add the middleware in the constructor of the controllers. I dislike it but it works.

I'm currently using Laravel 8 with a new project and found that the following solution works:

  1. Set the default middleware in kernel.php
'api' => [
        'throttle:40,1',
        'bindings',
    ],
  1. Remove the middleware throttle:40,1 from the specific route, and add the correct middleware throttle:15,3:
Route::post('login', 'Api\UserController@login')->withoutMiddleware('throttle:40,1')->middleware('throttle:15,3')->name('user.login');

If you do not remove the middleware, it will run the throttle middleware twice per request.

I also played around with $this->middleware( 'throttle:40,1' )->except( ['login'] ) in the constructor of Api\UserController, however that does not give the required result; it will just add the middleware for all but one method, it does not overwrite.

Upvotes: 8

nvahalik
nvahalik

Reputation: 559

Had this same question and just did some research. It doesn't appear that there is a way to overwrite the middleware configuration.

I, too, see that my middleware has updated in route:list but when resolving the middleware, it always uses a merged set of rules and so that initial api rule will end up overriding anything that defines something else over that.

You have a couple of options:

  1. Remove the throttle rule from the Kernel api middleware definition and then use a Route::group() to re-add that specific rule to the rest of the routes. Then, in the same file, you can create a new Route::group() which defines the custom throttle config.

    Route::group(['middleware' => 'throttle:120,1'], function () {
         ...
    });
    
    Route::group(['middleware' => 'throttle:15,3'], function () {
         ...
    });
    
  2. Create a custom api-auth.php file which is wrapped in a custom middleware group that you define just like the default api middleware. (You'll need to add another call in your RouteServiceProvider to load it like this:

    public function map() { 
        ...
        $this->mapCustomAuthRoutes();
    }
    
    protected function mapCustomAuthRoutes()
    {
        Route::middleware(['throttle:15,3', 'bindings'])
            ->namespace($this->namespace)
            ->as('api.')
            ->group(base_path('routes/api-auth.php'));
    }
    

Upvotes: 1

Related Questions