1
1
import 'package:core/core.dart' ;
2
2
import 'package:dart_frog/dart_frog.dart' ;
3
+ import 'package:flutter_news_app_api_server_full_source_code/src/config/environment_config.dart' ;
3
4
import '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' ;
5
9
import 'package:flutter_news_app_api_server_full_source_code/src/registry/model_registry.dart' ;
6
10
7
11
/// Middleware specific to the generic `/api/v1/data` route path.
8
12
///
9
13
/// This middleware chain performs the following in order:
10
14
/// 1. **Authentication Check (`requireAuthentication` ):** Ensures that the user
11
15
/// 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` ):**
13
19
/// - Validates the `model` query parameter.
14
20
/// - 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
18
23
/// and model-specific permissions based on the `ModelConfig` metadata.
19
24
/// If the user lacks permission, it throws a [ForbiddenException].
20
25
///
21
26
/// This setup ensures that data routes are protected, have the necessary
22
27
/// model-specific configuration available, and access is authorized before
23
28
/// reaching the final route handler.
24
29
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
+
25
58
// Helper middleware for model validation and context provision.
26
59
Middleware _modelValidationAndProviderMiddleware () {
27
60
return (handler) {
@@ -79,15 +112,19 @@ Handler middleware(Handler handler) {
79
112
// resulting in a 401 response via the global `errorHandler`).
80
113
// - If `User` is present, the request proceeds to the next middleware.
81
114
//
82
- // 2. `_modelValidationAndProviderMiddleware ()`:
115
+ // 2. `_dataRateLimiterMiddleware ()`:
83
116
// - 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.
84
123
// - It validates the `?model=` query parameter and provides the
85
124
// `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`.
89
126
//
90
- // 3 . `authorizationMiddleware()`:
127
+ // 4 . `authorizationMiddleware()`:
91
128
// - This runs if `_modelValidationAndProviderMiddleware()` passes.
92
129
// - It reads the `User`, `modelName`, and `ModelConfig` from the context.
93
130
// - It checks if the user has permission to perform the requested HTTP
@@ -97,14 +134,15 @@ Handler middleware(Handler handler) {
97
134
// - If successful, it calls the next handler in the chain (the actual
98
135
// route handler).
99
136
//
100
- // 4 . Actual Route Handler (from `index.dart` or `[id].dart`):
137
+ // 5 . Actual Route Handler (from `index.dart` or `[id].dart`):
101
138
// - This runs last, only if all preceding middlewares pass. It will have
102
139
// access to a non-null `User`, `ModelConfig`, and `modelName` from the context.
103
140
// - It performs the data operation and any necessary handler-level
104
141
// ownership checks (if flagged by `ModelActionPermission.requiresOwnershipCheck`).
105
142
//
106
143
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
109
147
.use (requireAuthentication ()); // Applied first (outermost)
110
148
}
0 commit comments