我目前正在尝试使用功能,管道和拦截器实现以下模式:
auth {
limit(1) {
get {
call.respond("Cake1")
}
}
}
在两个功能中,我都使用这个:
pipeline.insertPhaseAfter(ApplicationCallPipeline.Features, myCustomPhase)
pipeline.intercept(appTokenAuthPhase)
我遇到以下两个问题:
insertPhaseAfter
[Phase('Setup'),Phase('Monitoring'),Phase('Features'),Phase('Limit'),Phase('Call'),Phase('Fallback')]
[Phase('Setup'),Phase('Monitoring'),Phase('Features'),Phase('Auth'),Phase('Call'),Phase('Fallback')]
insertPhaseBefore
[Phase('Setup'),Phase('Monitoring'),Phase('Auth'),Phase('Features'),Phase('Call'),Phase('Fallback')]
[Phase('Setup'),Phase('Monitoring'),Phase('Limit'),Phase('Features'),Phase('Call'),Phase('Fallback')]
rate(100) {
route("/sub") {
rate(5) {
get("/critical") {
call.respondText("Hello, World!")
}
}
get("/profile/{id}") { TODO("...") }
}
}
因此对于/ sub / critical,仅应调用具有Rate(5)的拦截器,而应跳过Rate(100)。在当前架构中这可能吗?我看不到任何方法可以覆盖合并并删除阶段“ Limit”的“最后”拦截器以外的所有拦截器。对于所有管道,另一个“限制”应保留在原处,而没有孩子的“限制”。其他拦截器(如Auth)应照常执行。
答案 0 :(得分:0)
我将写给您第二部分的内容。我不确定它是否性感。基本上,当我使用自定义内容将新的孩子添加到路线时,我会计算路线中已有多少个具有相同选择器的父母。然后,我将这笔钱传递给拦截器,所以我知道当前孩子的嵌套位置是什么。
fun Route.test(
message: String,
build: Route.() -> Unit,
): Route {
val testRoute = createChild(SimpleSelector("message"))
application.feature(SimpleInterceptor).apply {
interceptPipeline(testRoute, message, testRoute.countSimpleSelectors())
}
testRoute.build()
return testRoute
}
fun Route.countSimpleSelectors(): Int =
(parent?.countSimpleSelectors() ?: 0) +
if (parent?.selector is SimpleSelector) {
1
} else {
0
}
然后在拦截器中添加与嵌套拦截器一样多的阶段。但是我以相反的顺序添加它们,这意味着最后添加的拦截器将首先运行。
fun interceptPipeline(
pipeline: ApplicationCallPipeline,
message: String,
nestingCounter: Int,
) {
pipeline.insertPhaseAfter(ApplicationCallPipeline.Features, Authentication.ChallengePhase)
val phases = (nestingCounter downTo 0).map {
simplePhase(it)
}
phases.fold(Authentication.ChallengePhase) { old, new ->
pipeline.insertPhaseAfter(old, new)
new
}
pipeline.intercept(phases.first()) {
val call = call
val simpleContext = SimpleContext.from(call)
TestPipeline().apply {
val subject = SimpleContext.from(call)
println("original subject: $message, new subject: ${subject.someMessage}")
subject.someMessage = message
}.execute(call, simpleContext)
}
}
现在,链中最新添加的拦截器将首先运行。剩下的就是让拦截器向管道添加上下文。该上下文可以是您想要的任何内容,因此您可以例如在该上下文中添加一个布尔值:isAlreadyHandled。完成后,第一个拦截器可以翻转它,随后的拦截器可以忽略管道。
我基于此:https://www.ximedes.com/2020-09-17/role-based-authorization-in-ktor/
以及随附的github存储库:https://github.com/ximedes/ktor-authorization
我使用了与那里相同的结构,只是添加了计数和上下文。我希望这会有所帮助!