csieflyman / multi-projects-architecture-with-Ktor

A Ktor real world example built on multi-projects architecture
MIT License
69 stars 8 forks source link

关于Authentication插件和Routing的疑问 #2

Closed LeIgHlEe closed 10 months ago

LeIgHlEe commented 10 months ago

Routing 是对整个 ApplicationCallPipeline.Call 做 intercept,而 Authentication 我大概看了下源码,都是在 ApplicationCallPipeline.Call 之前的,也就是鉴权动作会放在选取路由的前面。 那是否意味着,如果访问一个不存在的路径,其实报错不是因为404,而是因为没有访问权限?

csieflyman commented 10 months ago

我剛才看一下源碼 io.ktor.server.engine.BaseApplicationEngine 如果沒辦法 resolve route 而且你自己也沒設定 response status,就會依序回應 RoutingFailureStatusCode 及 HttpStatusCode.NotFound (404)

private fun Application.installDefaultInterceptors() {
    intercept(ApplicationCallPipeline.Fallback) {
        if (call.isHandled) return@intercept

        val status = call.response.status()
            ?: call.attributes.getOrNull(RoutingFailureStatusCode)
            ?: HttpStatusCode.NotFound

        call.respond(status)
    }

    intercept(ApplicationCallPipeline.Call) {
        verifyHostHeader()
    }
}

在 Route.txt 源碼 如果沒辦法 resolve ,就設置 resolveResult.errorStatusCode,預設值也是 404

    public suspend fun interceptor(context: PipelineContext<Unit, ApplicationCall>) {
        val resolveContext = RoutingResolveContext(this, context.call, tracers)
        when (val resolveResult = resolveContext.resolve()) {
            is RoutingResolveResult.Success ->
                executeResult(context, resolveResult.route, resolveResult.parameters)

            is RoutingResolveResult.Failure ->
                context.call.attributes.put(RoutingFailureStatusCode, resolveResult.errorStatusCode)
        }
    }

執行順序應該是 Route -> Authentication -> ApplicationCallPipeline.Call 所以如果 Route 沒辦法 resolve,就不會進入 Authentication 及 ApplicationCallPipeline.Call 直接回傳 404

除非你自已設置 call.attributes.put(RoutingFailureStatusCode) 或是嚐試在 StatusPages 覆寫你想要的 status code (我沒試過)

這是官方文件範例

install(StatusPages) {
    status(HttpStatusCode.NotFound) { call, status ->
        call.respondText(text = "404: Page Not Found", status = status)
    }
}
LeIgHlEe commented 10 months ago

非常感谢你的回答,我通过你给的代码示例和官方文件,从感性的角度来理解的话,大概是: 不管你有没有别人想要的东西,只要别人来拿,你就得验身。 而不是别人来拿的时候,你先帮忙看一眼有没有,没有的时候还亲切得告诉对方。 所以如果一个没有权限的请求进来,访问一个不存在的资源,也是优先提示没有权限。 再次感谢。