You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KTOR中表单登录后如何重定向回初始访问页面?

Ktor 登录后重定向回原受保护资源的解决方案

1. 在认证拦截中传递原请求URI到登录页

给auth-session认证添加失败挑战逻辑,将用户原本要访问的URI作为查询参数附加到登录跳转地址,确保登录页能拿到目标地址:

authenticate("auth-session") {
    get("/list") {
        // 你的业务逻辑实现
    }
    // 其他受auth-session保护的路由...
}.challenge { defaultScheme, realm ->
    // 获取当前请求的完整URI(包含查询参数)
    val redirectUri = call.request.uri
    // 对URI进行URL编码,避免特殊字符解析异常
    val encodedUri = java.net.URLEncoder.encode(redirectUri, "UTF-8")
    // 重定向到登录页并携带原地址参数
    call.respondRedirect("/login?redirectUri=$encodedUri")
    complete()
}

2. 登录页接收并保存原地址

修改登录的GET路由,接收redirectUri参数,可选择存入临时session或传递给模板,确保POST登录时能获取到:

方式一:存入临时Session(推荐)

先定义临时存储重定向地址的Session类:

data class TempRedirectSession(val redirectUri: String)

在Session配置中注册这个临时Session:

install(Sessions) {
    cookie<UserSession>("user_session")
    cookie<TempRedirectSession>("temp_redirect") // 新增临时Session配置
}

然后修改登录GET路由:

route("/login") {
    get {
        val redirectUri = call.request.queryParameters["redirectUri"]?.let {
            // 解码URL参数
            java.net.URLDecoder.decode(it, "UTF-8")
        } ?: "/"
        // 将原地址存入临时Session
        call.sessions.set(TempRedirectSession(redirectUri))
        call.respond(FreeMarkerContent("login.ftl", model = null))
    }

    // 后续POST登录逻辑...
}

方式二:传递给模板

如果不想用临时Session,可将参数传递给模板,让表单提交时携带:

route("/login") {
    get {
        val redirectUri = call.request.queryParameters["redirectUri"]?.let {
            java.net.URLDecoder.decode(it, "UTF-8")
        } ?: "/"
        call.respond(FreeMarkerContent("login.ftl", mapOf("redirectUri" to redirectUri)))
    }
}

同时在login.ftl的表单中添加隐藏字段:

<form method="post">
    <!-- 用户名、密码等表单字段 -->
    <input type="hidden" name="redirectUri" value="${redirectUri}">
    <button type="submit">登录</button>
</form>

3. 登录成功后重定向到原地址

修改登录POST路由,获取保存的redirectUri,完成登录后跳转至目标地址:

authenticate("auth-form") {
    post {
        val loginUser = call.principal<UserIdPrincipal>()?.name.toString()
        val session = UserSession(loginUser, AccessLevel.USER)
        call.sessions.set(session)

        // 获取重定向地址:优先取表单参数(方式二),再取临时Session(方式一),默认跳转到首页
        val redirectUri = call.request.formParameters["redirectUri"]
            ?: call.sessions.get<TempRedirectSession>()?.redirectUri
            ?: "/"
        
        // 清除临时Session(如果用了方式一)
        call.sessions.clear<TempRedirectSession>()

        // 重定向到用户原本要访问的资源
        call.respondRedirect(redirectUri)
    }
}

内容的提问来源于stack exchange,提问作者Andrey Karpenkov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:31:07