如何在Http4K Kotlin中为不同ContractRoute路由应用不同过滤器?
在Http4K中实现部分路由认证、部分路由免认证的正确方式
你当前的写法是把过滤器直接绑定到单个路由的handler上,但Http4K的Contract路由机制下,这种方式可能不会按预期生效。正确的做法是先对路由组分别应用过滤器,再合并路由,而不是在单个路由的handler上叠加过滤器。
修改后的实现代码
// 1. 抽离所有路由通用的基础过滤器链 private val baseFilters = ResetMDCFilter() .then(EnvironmentMDCFilter(environment)) .then(RequestLogFilter()) .then(ResponseLogFilter()) .then(CorrelationIdMDCFilter()) .then(ErrorCodeCatchAllFilter(logger)) .then(ErrorCodeLensFailureFilter(logger)) // 2. 定义带认证的过滤器链(基础过滤器+鉴权过滤器) private val authFilters = AuthorisationFilter(jwtVerifier).then(baseFilters) // 3. 拆分路由为两个Contract组:免认证路由、需认证路由 private fun noAuthRoutes() = contract { val apiDescription = "Some description for API" renderer = OpenApi3( ApiInfo( title = "Title", version = "v1.0.0", description = apiDescription ), CustomJackson ) descriptionPath = "/docs/swaggerV2.json" routes += pingRoute() } private fun authRoutes() = contract { val apiDescription = "Some description for API" renderer = OpenApi3( ApiInfo( title = "Title", version = "v1.0.0", description = apiDescription ), CustomJackson ) descriptionPath = "/docs/swaggerV2.json" routes += getCustomerRoute() } // 4. 为两组路由分别绑定过滤器,再合并为最终的HttpHandler val routes: HttpHandler = ("/account" bind baseFilters.then(noAuthRoutes())) + ("/account" bind authFilters.then(authRoutes())) // 单个路由简化定义,无需再绑定过滤器(已在路由组层面处理) private fun pingRoute(): ContractRoute { return "/ping" meta { summary = "ping" description = "Ping Api" returning(Status.OK to "The result") } bindContract Method.GET to { _ -> Response(Status.OK).body("pong")} } private fun getCustomerRoute(): ContractRoute { return "/customer" / Path.string().map(::CustomerNumber).of("customerNumber") meta { summary = "Gets customer account information" description = "Gets customer account information" returning( status = Status.OK, body = CustomerAccountDataResponse.bodyLens to CustomerAccountDataResponse() ) } bindContract Method.GET to accountEndpoints::getCustomerAccount }
逻辑说明
- 把所有路由共用的过滤器抽成
baseFilters,避免重复代码 - 将路由拆分为两个独立的Contract,分别对应免认证和需认证的路由集合
- 对每个Contract路由组应用对应的过滤器链,再通过
+运算符合并成最终的HttpHandler - 单个路由的handler不再需要叠加过滤器,逻辑更清晰,同时保证过滤器能正确作用到目标路由上
替代简化方案(无需拆分Contract)
如果路由数量不多,也可以直接按路径分组绑定过滤器:
// 基础过滤器和认证过滤器定义不变 private val baseFilters = ... private val authFilters = ... // 定义包含所有路由的Contract private val allRoutesContract = contract { val apiDescription = "Some description for API" renderer = OpenApi3( ApiInfo( title = "Title", version = "v1.0.0", description = apiDescription ), CustomJackson ) descriptionPath = "/docs/swaggerV2.json" routes += pingRoute() routes += getCustomerRoute() } // 按路径匹配分别应用过滤器 val routes: HttpHandler = ("/account/ping" bind baseFilters.then(allRoutesContract)) + ("/account/customer" bind authFilters.then(allRoutesContract))
内容的提问来源于stack exchange,提问作者Akshay Mahajan
相关产品推荐
相关产品推荐

