Hello, laravel web developers! In this article, I'll show you how to implement custom middleware in Laravel 11 to rate-limit API requests based on user roles or other criteria. Whether you want to apply different limits for admins and regular users or handle high-traffic scenarios, this step-by-step guide will walk you through the process.
I'll also discuss how to manage rate limits effectively for high-traffic applications, ensuring your API remains responsive and secure.
First, let's create a new middleware for rate limiting. Run the following Artisan command to generate the middleware file:
php artisan make:middleware RoleBasedRateLimiter
This command will create a file in the app/Http/Middleware
directory.
Open the generated RoleBasedRateLimiter.php
file and modify it to define custom rate-limiting logic based on the user's role. Here's an example:
<?php
namespace App\Http\Middleware;
use Illuminate\Support\Facades\RateLimiter;
use Closure;
use Illuminate\Http\Request;
class RoleBasedRateLimiter
{
public function handle(Request $request, Closure $next)
{
$user = $request->user();
// Check if the user is logged in and has a role
if ($user && $user->role) {
// Different rate limits based on roles
if ($user->role === 'admin') {
$this->setRateLimit($request, 'admin', 100, 1); // 100 requests per minute for admins
} else {
$this->setRateLimit($request, 'user', 60, 1); // 60 requests per minute for regular users
}
}
return $next($request);
}
protected function setRateLimit(Request $request, $role, $maxAttempts, $decayMinutes)
{
RateLimiter::for($role, function () use ($request, $maxAttempts, $decayMinutes) {
return Limit::perMinute($maxAttempts)->by(optional($request->user())->id ?: $request->ip());
});
// Check if the user has exceeded the rate limit
if (RateLimiter::tooManyAttempts($role, optional($request->user())->id ?: $request->ip())) {
return response()->json([
'message' => 'Too many requests, please slow down.',
], 429);
}
}
}
Next, register your custom middleware in the bootstrap/app.php file.
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'role.rate.limit' => \App\Http\Middleware\RoleBasedRateLimiter::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
Now that the middleware is created, let's apply it to specific API routes. Open the routes/api.php
file and attach the middleware to routes like this:
Route::middleware(['auth:sanctum', 'role.rate.limit'])->group(function () {
Route::get('/admin/dashboard', [AdminController::class, 'dashboard']);
Route::get('/user/profile', [UserController::class, 'profile']);
});
You can now test the rate-limiting functionality by making API requests as different users. Try accessing the /admin/dashboard
and /user/profile
routes with admin and regular user roles, respectively. If you exceed the rate limits, the API will respond with a 429 Too Many Requests
status.
For high-traffic applications, it's important to optimize the rate-limiting logic. Consider these best practices:
Cache Rate Limit Counters: Use Redis or Memcached to store rate limit counters, improving performance for large-scale applications.
Custom Rate Limiting by IP: If users aren’t logged in, rate limit by IP address to prevent abuse from unauthenticated users.
Monitoring and Alerts: Use tools like Laravel Horizon or external services like New Relic to monitor rate-limiting metrics and handle traffic spikes proactively.
You might also like: