@@ -36,7 +36,7 @@ Middleware _dataRateLimiterMiddleware() {
3636 };
3737}
3838
39- // Helper middleware for model validation and context provision.
39+ /// Helper middleware for model validation and context provision.
4040Middleware _modelValidationAndProviderMiddleware () {
4141 return (handler) {
4242 // This 'handler' is the next handler in the chain,
@@ -76,6 +76,56 @@ Middleware _modelValidationAndProviderMiddleware() {
7676 };
7777}
7878
79+ /// Helper middleware to conditionally apply authentication based on
80+ /// `ModelConfig` .
81+ ///
82+ /// This middleware checks the `requiresAuthentication` flag on the
83+ /// `ModelActionPermission` for the current model and HTTP method.
84+ /// If authentication is required, it calls `requireAuthentication()` .
85+ /// If not, it simply passes the request through, allowing public access.
86+ Middleware _conditionalAuthenticationMiddleware () {
87+ return (handler) {
88+ return (context) {
89+ final modelConfig = context.read <ModelConfig <dynamic >>();
90+ final method = context.request.method;
91+
92+ ModelActionPermission requiredPermissionConfig;
93+ switch (method) {
94+ case HttpMethod .get :
95+ // Differentiate GET based on whether it's a collection or item request
96+ final isCollectionRequest =
97+ context.request.uri.path == '/api/v1/data' ;
98+ if (isCollectionRequest) {
99+ requiredPermissionConfig = modelConfig.getCollectionPermission;
100+ } else {
101+ requiredPermissionConfig = modelConfig.getItemPermission;
102+ }
103+ case HttpMethod .post:
104+ requiredPermissionConfig = modelConfig.postPermission;
105+ case HttpMethod .put:
106+ requiredPermissionConfig = modelConfig.putPermission;
107+ case HttpMethod .delete:
108+ requiredPermissionConfig = modelConfig.deletePermission;
109+ default :
110+ // For unsupported methods, assume authentication is required
111+ // or let subsequent middleware/route handler deal with it.
112+ requiredPermissionConfig = const ModelActionPermission (
113+ type: RequiredPermissionType .unsupported,
114+ requiresAuthentication: true ,
115+ );
116+ }
117+
118+ if (requiredPermissionConfig.requiresAuthentication) {
119+ // If authentication is required, apply the requireAuthentication middleware.
120+ return requireAuthentication ()(handler)(context);
121+ } else {
122+ // If authentication is not required, simply pass the request through.
123+ return handler (context);
124+ }
125+ };
126+ };
127+ }
128+
79129// Main middleware exported for the /api/v1/data route group.
80130Handler middleware (Handler handler) {
81131 // This 'handler' is the actual route handler from index.dart or [id].dart.
@@ -84,17 +134,15 @@ Handler middleware(Handler handler) {
84134 // the last .use() call in the chain represents the outermost middleware layer.
85135 // Therefore, the execution order for an incoming request is:
86136 //
87- // 1. `requireAuthentication()`:
88- // - This runs first. It relies on `authenticationProvider()` (from the
89- // parent `/api/v1/_middleware.dart`) having already attempted to
90- // authenticate the user and provide `User?` into the context.
91- // - If `User` is null (no valid authentication), `requireAuthentication()`
92- // throws an `UnauthorizedException`, and the request is aborted (usually
93- // resulting in a 401 response via the global `errorHandler`).
94- // - If `User` is present, the request proceeds to the next middleware.
137+ // 1. `_conditionalAuthenticationMiddleware()`:
138+ // - This runs first. It dynamically decides whether to apply
139+ // `requireAuthentication()` based on the `ModelConfig` for the
140+ // requested model and HTTP method.
141+ // - If authentication is required and the user is not authenticated,
142+ // it throws an `UnauthorizedException`.
95143 //
96144 // 2. `_dataRateLimiterMiddleware()`:
97- // - This runs if `requireAuthentication()` passes.
145+ // - This runs if authentication (if required) passes.
98146 // - It checks if the user has a bypass permission. If not, it applies
99147 // the configured rate limit based on the user's ID.
100148 // - If the limit is exceeded, it throws a `ForbiddenException`.
@@ -117,13 +165,14 @@ Handler middleware(Handler handler) {
117165 //
118166 // 5. Actual Route Handler (from `index.dart` or `[id].dart`):
119167 // - This runs last, only if all preceding middlewares pass. It will have
120- // access to a non-null `User`, `ModelConfig`, and `modelName` from the context.
168+ // access to a non-null `User` (if authenticated), `ModelConfig`, and
169+ // `modelName` from the context.
121170 // - It performs the data operation and any necessary handler-level
122171 // ownership checks (if flagged by `ModelActionPermission.requiresOwnershipCheck`).
123172 //
124173 return handler
125174 .use (authorizationMiddleware ()) // Applied fourth (inner-most)
126175 .use (_modelValidationAndProviderMiddleware ()) // Applied third
127176 .use (_dataRateLimiterMiddleware ()) // Applied second
128- .use (requireAuthentication ()); // Applied first (outermost)
177+ .use (_conditionalAuthenticationMiddleware ()); // Applied first (outermost)
129178}
0 commit comments