11import 'package:core/core.dart' ;
22import 'package:dart_frog/dart_frog.dart' ;
3+ import 'package:flutter_news_app_api_server_full_source_code/src/config/environment_config.dart' ;
34import 'package:flutter_news_app_api_server_full_source_code/src/middlewares/authentication_middleware.dart' ;
4- import 'package:flutter_news_app_api_server_full_source_code/src/middlewares/authorization_middleware.dart' ; // Import authorization middleware
5+ import 'package:flutter_news_app_api_server_full_source_code/src/middlewares/authorization_middleware.dart' ;
6+ import 'package:flutter_news_app_api_server_full_source_code/src/middlewares/rate_limiter_middleware.dart' ;
7+ import 'package:flutter_news_app_api_server_full_source_code/src/rbac/permission_service.dart' ;
8+ import 'package:flutter_news_app_api_server_full_source_code/src/rbac/permissions.dart' ;
59import 'package:flutter_news_app_api_server_full_source_code/src/registry/model_registry.dart' ;
610
711/// Middleware specific to the generic `/api/v1/data` route path.
812///
913/// This middleware chain performs the following in order:
1014/// 1. **Authentication Check (`requireAuthentication` ):** Ensures that the user
1115/// is authenticated. If not, it aborts the request with a 401.
12- /// 2. **Model Validation & Context Provision (`_modelValidationAndProviderMiddleware` ):**
16+ /// 2. **Data Rate Limiting (`_dataRateLimiterMiddleware` ):** Applies a
17+ /// configurable, user-centric rate limit. Bypassed by admin/publisher roles.
18+ /// 3. **Model Validation & Context Provision (`_modelValidationAndProviderMiddleware` ):**
1319/// - Validates the `model` query parameter.
1420/// - Looks up the `ModelConfig` from the `ModelRegistryMap`.
15- /// - Provides the `ModelConfig` and `modelName` into the request context
16- /// for downstream middleware and route handlers.
17- /// 3. **Authorization Check (`authorizationMiddleware` ):** Enforces role-based
21+ /// - Provides the `ModelConfig` and `modelName` into the request context.
22+ /// 4. **Authorization Check (`authorizationMiddleware` ):** Enforces role-based
1823/// and model-specific permissions based on the `ModelConfig` metadata.
1924/// If the user lacks permission, it throws a [ForbiddenException].
2025///
2126/// This setup ensures that data routes are protected, have the necessary
2227/// model-specific configuration available, and access is authorized before
2328/// reaching the final route handler.
2429
30+ // Helper middleware for applying rate limiting to the data routes.
31+ Middleware _dataRateLimiterMiddleware () {
32+ return (handler) {
33+ return (context) {
34+ final user = context.read <User >();
35+ final permissionService = context.read <PermissionService >();
36+
37+ // Users with the bypass permission are not rate-limited.
38+ if (permissionService.hasPermission (
39+ user,
40+ Permissions .rateLimitingBypass,
41+ )) {
42+ return handler (context);
43+ }
44+
45+ // For all other users, apply the configured rate limit.
46+ // The key is the user's ID, ensuring the limit is per-user.
47+ final rateLimitHandler = rateLimiter (
48+ limit: EnvironmentConfig .rateLimitDataApiLimit,
49+ window: EnvironmentConfig .rateLimitDataApiWindow,
50+ keyExtractor: (context) async => context.read <User >().id,
51+ )(handler);
52+
53+ return rateLimitHandler (context);
54+ };
55+ };
56+ }
57+
2558// Helper middleware for model validation and context provision.
2659Middleware _modelValidationAndProviderMiddleware () {
2760 return (handler) {
@@ -79,15 +112,19 @@ Handler middleware(Handler handler) {
79112 // resulting in a 401 response via the global `errorHandler`).
80113 // - If `User` is present, the request proceeds to the next middleware.
81114 //
82- // 2. `_modelValidationAndProviderMiddleware ()`:
115+ // 2. `_dataRateLimiterMiddleware ()`:
83116 // - This runs if `requireAuthentication()` passes.
117+ // - It checks if the user has a bypass permission. If not, it applies
118+ // the configured rate limit based on the user's ID.
119+ // - If the limit is exceeded, it throws a `ForbiddenException`.
120+ //
121+ // 3. `_modelValidationAndProviderMiddleware()`:
122+ // - This runs if rate limiting passes.
84123 // - It validates the `?model=` query parameter and provides the
85124 // `ModelConfig` and `modelName` into the context.
86- // - If model validation fails, it throws a BadRequestException, caught
87- // by the global errorHandler.
88- // - If successful, it calls the next handler in the chain (authorizationMiddleware).
125+ // - If model validation fails, it throws a `BadRequestException`.
89126 //
90- // 3 . `authorizationMiddleware()`:
127+ // 4 . `authorizationMiddleware()`:
91128 // - This runs if `_modelValidationAndProviderMiddleware()` passes.
92129 // - It reads the `User`, `modelName`, and `ModelConfig` from the context.
93130 // - It checks if the user has permission to perform the requested HTTP
@@ -97,14 +134,15 @@ Handler middleware(Handler handler) {
97134 // - If successful, it calls the next handler in the chain (the actual
98135 // route handler).
99136 //
100- // 4 . Actual Route Handler (from `index.dart` or `[id].dart`):
137+ // 5 . Actual Route Handler (from `index.dart` or `[id].dart`):
101138 // - This runs last, only if all preceding middlewares pass. It will have
102139 // access to a non-null `User`, `ModelConfig`, and `modelName` from the context.
103140 // - It performs the data operation and any necessary handler-level
104141 // ownership checks (if flagged by `ModelActionPermission.requiresOwnershipCheck`).
105142 //
106143 return handler
107- .use (authorizationMiddleware ()) // Applied third (inner)
108- .use (_modelValidationAndProviderMiddleware ()) // Applied second
144+ .use (authorizationMiddleware ()) // Applied fourth (inner-most)
145+ .use (_modelValidationAndProviderMiddleware ()) // Applied third
146+ .use (_dataRateLimiterMiddleware ()) // Applied second
109147 .use (requireAuthentication ()); // Applied first (outermost)
110148}
0 commit comments