slogan3

Integreer Geavanceerde Laravel API Rate Limiting met Flexibele Configuratie

description

Met deze prompt kan de gebruiker een flexibele en effectieve rate limiting strategie ontwikkelen die overbelasting van de API voorkomt, de veiligheid verhoogt en een betere gebruikerservaring biedt. Het is specifieker en geavanceerder dan standaard oplossingen en helpt bij het beheren van verschillende gebruikersgroepen.

prompt

Help mij een geavanceerd rate limiting systeem te ontwerpen voor mijn Laravel API dat verschillende limieten toepast op basis van <het type gebruiker of API sleutel> en <s ...

try_prompt

generate_helper
disclaimerOnPageApi

ai_answers

provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een uitgebreide uitleg over het ontwerpen van een geavanceerd rate limiting systeem in Laravel dat verschillende limieten toepast op basis van routes, inclusief configuratie, implementatie en testen. --- ### 1. **Concept en architectuur** Je wilt verschillende limieten toepassen: - **Standaard limiet** voor algemene routes - **Specifieke limieten** voor `/api/v1/orders` - **Specifieke limieten** voor `/api/v1/users` Laravel biedt standaard ondersteuning voor rate limiting via de `throttle` middleware en de `RateLimiter` klasse, waarmee je flexibele limieten kunt configureren. --- ### 2. **Configuratie van limieten** #### a. **Definieer limieten in `RouteServiceProvider` of via `Route::middleware()`** Je kunt custom limieten definiëren in `app/Providers/RouteServiceProvider.php` of in een dedicated RateLimiter configuratiebestand. **Voorbeeld:** ```php use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Support\Facades\RateLimiter; /** * Definieer de limieten. */ protected function configureRateLimiting() { RateLimiter::for('global', function ($request) { return Limit::perMinute(100); // Standaard limiet 100 per minuut }); RateLimiter::for('orders', function ($request) { return Limit::perMinute(50)->by($request->user()?->id ?: $request->ip()); // Orders limiet }); RateLimiter::for('users', function ($request) { return Limit::perMinute(20)->by($request->user()?->id ?: $request->ip()); // Users limiet }); } ``` #### b. **Roep `configureRateLimiting()` aan in `boot()`** ```php public function boot() { $this->configureRateLimiting(); parent::boot(); } ``` --- ### 3. **Gebruik van middleware in routes** Je moet de juiste limietgroep toewijzen aan je routes via de `throttle` middleware: ```php Route::middleware(['throttle:global'])->group(function () { // Algemene routes }); Route::middleware(['throttle:orders'])->group(function () { Route::apiResource('orders', OrderController::class); }); Route::middleware(['throttle:users'])->group(function () { Route::apiResource('users', UserController::class); }); ``` Of direct per route: ```php Route::get('/api/v1/orders', [OrderController::class, 'index'])->middleware('throttle:orders'); Route::get('/api/v1/users', [UserController::class, 'index'])->middleware('throttle:users'); ``` --- ### 4. **Cache driver instellen** Laravel gebruikt standaard de cache driver voor rate limiting. Zorg dat je `.env` correct is ingesteld, bijvoorbeeld: ```env CACHE_DRIVER=redis ``` Of een andere driver zoals `memcached` of `file`. Redis is aanbevolen voor hoge prestaties en schaalbaarheid. --- ### 5. **Testen van het systeem** #### a. **Unit tests** Maak tests die het limiet gedrag controleren: ```php public function test_order_rate_limit() { for ($i = 0; $i < 50; $i++) { $response = $this->actingAs($user)->get('/api/v1/orders'); $response->assertStatus(200); } // De 51e aanvraag moet falen $response = $this->actingAs($user)->get('/api/v1/orders'); $response->assertStatus(429); } ``` #### b. **Gebruik Postman of cURL** Doe herhaalde requests en observeer de headers: - `X-RateLimit-Limit` - `X-RateLimit-Remaining` - `Retry-After` voorbeeld: ```bash curl -i https://jouwapi.nl/api/v1/orders ``` --- ### 6. **Samenvatting** - **Definieer limieten** in `RateLimiter::for()`. - **Koppel limieten** aan routes via de `throttle` middleware. - **Gebruik cache driver** zoals Redis voor prestaties. - **Test** je limieten uitgebreid met geautomatiseerde tests en handmatige checks. --- ### 7. **Aanvullende tips** - Overweeg dynamische limieten op basis van gebruikersrollen. - Voeg logging toe voor trage of geblokkeerde requests. - Gebruik `RateLimiter` callback functies voor complexere limietlogica. --- Indien je verdere hulp nodig hebt bij specifieke implementaties of codevoorbeelden, laat het gerust weten!
provider: deepseek
model: deepseek-chat
Zeker, ik help je een geavanceerd rate limiting systeem te ontwerpen voor je Laravel API. Hier is een complete implementatiegids: ## 1. Configuratie in `config/rate-limiter.php` ```php <?php return [ 'defaults' => [ 'limiter' => 'redis', 'max_attempts' => 60, 'decay_minutes' => 1, ], 'limits' => [ 'global' => [ 'max_attempts' => 1000, 'decay_minutes' => 1440, // 24 uur ], 'api_v1_orders' => [ 'max_attempts' => 100, 'decay_minutes' => 1, 'by' => 'user_id', // of 'ip' ], 'api_v1_users' => [ 'max_attempts' => 30, 'decay_minutes' => 1, 'by' => 'ip', ], 'strict' => [ 'max_attempts' => 5, 'decay_minutes' => 1, 'by' => 'ip', ], ], ]; ``` ## 2. Aangepaste Rate Limiting Middleware Maak een nieuwe middleware: `app/Http/Middleware/AdvancedRateLimit.php` ```php <?php namespace App\Http\Middleware; use Closure; use Illuminate\Cache\RateLimiter; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class AdvancedRateLimit { protected $limiter; public function __construct(RateLimiter $limiter) { $this->limiter = $limiter; } public function handle(Request $request, Closure $next, $limitName) { $limitConfig = config("rate-limiter.limits.{$limitName}"); if (!$limitConfig) { return $next($request); } $key = $this->resolveRequestSignature($request, $limitConfig); $maxAttempts = $limitConfig['max_attempts']; $decayMinutes = $limitConfig['decay_minutes']; if ($this->limiter->tooManyAttempts($key, $maxAttempts)) { return $this->buildResponse($key, $maxAttempts); } $this->limiter->hit($key, $decayMinutes * 60); $response = $next($request); return $this->addHeaders( $response, $maxAttempts, $this->calculateRemainingAttempts($key, $maxAttempts) ); } protected function resolveRequestSignature(Request $request, array $config) { $identifier = match($config['by'] ?? 'ip') { 'user_id' => $request->user()?->id ?: $request->ip(), 'api_key' => $request->header('API-Key') ?: $request->ip(), default => $request->ip() }; return sha1("{$config['by']}|{$identifier}"); } protected function buildResponse($key, $maxAttempts) { $retryAfter = $this->limiter->availableIn($key); return response()->json([ 'error' => 'Too Many Attempts', 'retry_after' => $retryAfter, 'limit' => $maxAttempts ], 429)->withHeaders([ 'Retry-After' => $retryAfter, 'X-RateLimit-Limit' => $maxAttempts, 'X-RateLimit-Remaining' => 0, ]); } protected function addHeaders(Response $response, $maxAttempts, $remaining) { $response->headers->add([ 'X-RateLimit-Limit' => $maxAttempts, 'X-RateLimit-Remaining' => $remaining, ]); return $response; } protected function calculateRemainingAttempts($key, $maxAttempts) { return max(0, $maxAttempts - $this->limiter->attempts($key)); } } ``` ## 3. Route Configuratie In `routes/api.php`: ```php <?php use App\Http\Middleware\AdvancedRateLimit; use Illuminate\Support\Facades\Route; // Globale API limiet Route::middleware(['auth:api', 'throttle:api_v1_global'])->group(function () { // Orders endpoint - striktere limiet Route::prefix('orders')->middleware(AdvancedRateLimit::class . ':api_v1_orders')->group(function () { Route::get('/', [OrderController::class, 'index']); Route::post('/', [OrderController::class, 'store']); Route::put('/{order}', [OrderController::class, 'update']); }); // Users endpoint - andere limiet Route::prefix('users')->middleware(AdvancedRateLimit::class . ':api_v1_users')->group(function () { Route::get('/', [UserController::class, 'index']); Route::get('/{user}', [UserController::class, 'show']); }); // Kritieke endpoints - zeer strikte limiet Route::prefix('auth')->middleware(AdvancedRateLimit::class . ':strict')->group(function () { Route::post('/login', [AuthController::class, 'login']); Route::post('/register', [AuthController::class, 'register']); }); }); ``` ## 4. Cache Driver Configuratie (Redis aanbevolen) In `.env`: ```env CACHE_DRIVER=redis REDIS_CLIENT=predis REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 ``` In `config/database.php`: ```php 'redis' => [ 'client' => env('REDIS_CLIENT', 'predis'), 'options' => [ 'cluster' => env('REDIS_CLUSTER', 'redis'), 'prefix' => env('REDIS_PREFIX', 'laravel_rate_limit_'), ], 'default' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_DB', '0'), ], ], ``` ## 5. Testen van je Rate Limiting Maak testcases in `tests/Feature/RateLimitingTest.php`: ```php <?php namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Tests\TestCase; use App\Models\User; class RateLimitingTest extends TestCase { use RefreshDatabase; public function test_orders_endpoint_rate_limiting() { $user = User::factory()->create(); // Eerste 100 requests moeten slagen for ($i = 0; $i < 100; $i++) { $response = $this->actingAs($user) ->getJson('/api/v1/orders'); $response->assertStatus(200); } // 101e request moet falen $response = $this->actingAs($user) ->getJson('/api/v1/orders'); $response->assertStatus(429); } public function test_different_limits_for_different_endpoints() { $user = User::factory()->create(); // Orders endpoint limiet bereiken for ($i = 0; $i < 100; $i++) { $this->actingAs($user)->getJson('/api/v1/orders'); } // Users endpoint moet nog werken $response = $this->actingAs($user) ->getJson('/api/v1/users'); $response->assertStatus(200); } public function test_rate_limit_headers() { $user = User::factory()->create(); $response = $this->actingAs($user) ->getJson('/api/v1/orders'); $response->assertHeader('X-RateLimit-Limit'); $response->assertHeader('X-RateLimit-Remaining'); } public function test_rate_limit_reset_after_timeout() { $user = User::factory()->create(); // Limiet bereiken for ($i = 0; $i < 100; $i++) { $this->actingAs($user)->getJson('/api/v1/orders'); } // Wachten tot limiet reset sleep(61); // Moet weer werken $response = $this->actingAs($user) ->getJson('/api/v1/orders'); $response->assertStatus(200); } } ``` ## 6. Monitoring en Logging Voeg monitoring toe in `app/Providers/EventServiceProvider.php`: ```php protected $listen = [ 'Illuminate\Cache\Events\RateLimited' => [ 'App\Listeners\LogRateLimitedRequest', ], ]; ``` Maak een listener: `app/Listeners/LogRateLimitedRequest.php` ```php <?php namespace App\Listeners; use Illuminate\Cache\Events\RateLimited; use Illuminate\Support\Facades\Log; class LogRateLimitedRequest { public function handle(RateLimited $event) { Log::warning('Rate limit exceeded', [ 'key' => $event->key, 'max_attempts' => $event->maxAttempts, 'ip' => request()->ip(), 'url' => request()->fullUrl(), 'user_id' => optional(request()->user())->id, ]); } } ``` ## 7. Gebruik ```bash # Middleware registreren in app/Http/Kernel.php protected $middlewareAliases = [ 'advanced.rate.limit' => \App\Http\Middleware\AdvancedRateLimit::class, ]; # Testen uitvoeren php artisan test tests/Feature/RateLimitingTest.php # Redis status controleren redis-cli info stats | grep instantaneous_ops_per_sec ``` Dit systeem biedt: - Verschillende limieten per endpoint - Flexibele identificatie (IP, user_id, API key) - Duidelijke headers voor clients - Uitgebreide logging en monitoring - Eenvoudige configuratie en onderhoud Het gebruikt Redis voor optimale performance en schaalbaarheid in productieomgevingen.