configureRateLimiting(); $this->routes(function () { Route::prefix('api') ->middleware(['api']) ->namespace($this->namespace) ->group(base_path('routes/admin-media.php')); Route::prefix('api') ->middleware(['api', 'json.response']) ->namespace($this->namespace) ->group(base_path('routes/api.php')); Route::middleware(['api', 'json.response']) ->namespace($this->namespace) ->group(base_path('routes/client.php')); Route::middleware('web') ->namespace($this->namespace) ->group(base_path('routes/web.php')); }); } /** * Configure the rate limiters for the application. * * @return void */ protected function configureRateLimiting() { RateLimiter::for('api', function (Request $request) { // Admin SPA makes many parallel requests per page — use a higher limit for authenticated users // Guard mặc định là admin → khách (JWT guard client) phải lấy riêng, nếu không mọi khách bị đếm theo IP. $key = ($admin = $request->user()) ? 'admin:' . $admin->id : (($client = $request->user('client')) ? 'client:' . $client->id : null); return Limit::perMinute($key ? 300 : 60)->by($key ?: $request->ip()); }); RateLimiter::for('invoice-lookup', fn (Request $request) => [ Limit::perMinute(10)->by('invoice-lookup|' . strtoupper((string) $request->input('invoice_number'))), Limit::perMinute(30)->by('invoice-lookup|ip|' . $request->ip()), ]); // Auth endpoint của khách (login/verify/forgot...). portal-client gọi API từ Next server nên // IP gần như luôn là IP của Next → khoá theo route + email, không theo IP (tránh chặn chung mọi khách). RateLimiter::for('client-auth', function (Request $request) { $email = strtolower(trim((string) $request->input('email'))); $route = $request->route()?->getName(); $byEmail = Limit::perMinute(5)->by($route . '|' . ($email ?: $request->ip())); $perIpHourly = [ 'api.client.register' => 5, 'api.client.resend-verify' => 10, ]; if (!isset($perIpHourly[$route])) { return $byEmail; } return [$byEmail, Limit::perHour($perIpHourly[$route])->by($route . '|ip|' . $request->ip())]; }); } }