Перенаправить обратно на начальную страницу после входа в форму в KTOR?

У меня есть защищенный ресурс в KTOR, который требует аутентификации через сеанс аутентификации.

authenticate("auth-session") {
     get("/list") {...}

route("/login") {
     get { call.respond(FreeMarkerContent("login.ftl", model = null)) }
     
     authenticate("auth-form") {
     post {
        val loginUser = call.principal<UserIdPrincipal>()?.name.toString()
            val session = UserSession(loginUser, AccessLevel.USER )
            call.sessions.set(session)
            call.respondRedirect("/")
           }
     }

Можно ли захватить исходный ресурс (т. е. «/list») и перенаправить его обратно вместо «/»? У меня есть другие ресурсы, защищенные сеансом аутентификации, и все они требуют разных URI перенаправления. Я ценю помощь, так как не смог найти решения в другом месте.

Я пытался захватить заголовок реферера, но он теряется после операций получения/отправки.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете передать исходный запрошенный URL-адрес на маршрут /login POST через параметр запроса. В вызове провайдера аутентификации сеанса клиент может быть перенаправлен на страницу /login с параметром запроса, который затем можно вставить в действие формы в шаблоне login.ftl. Если аутентификация прошла успешно, значение параметра запроса можно использовать для окончательного перенаправления. Вот полный фрагмент кода:

import freemarker.cache.ClassTemplateLoader
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.engine.*
import io.ktor.server.freemarker.*
import io.ktor.server.netty.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.sessions.*

fun main() {
    embeddedServer(Netty, port = 8080) {
        install(FreeMarker) {
            templateLoader = ClassTemplateLoader(this::class.java.classLoader, "templates")
        }
        install(Sessions) {
            cookie<UserSession>("user_session") {
                cookie.path = "/"
                cookie.maxAgeInSeconds = 60
            }
        }

        install(Authentication) {
            session<UserSession>("auth-session") {
                validate { session ->
                    if (session.name.startsWith("jet")) {
                        session
                    } else {
                        null
                    }
                }
                challenge {
                    call.respondRedirect("/login?origin=${call.request.uri}")
                }
            }

            form("auth-form") {
                userParamName = "username"
                passwordParamName = "password"
                validate { credentials ->
                    if (credentials.name == "jetbrains" && credentials.password == "foobar") {
                        UserIdPrincipal(credentials.name)
                    } else {
                        null
                    }
                }
                challenge {
                    call.respond(HttpStatusCode.Unauthorized, "Credentials are not valid")
                }
            }
        }

        routing {
            authenticate("auth-session") {
                get("/list") { call.respondText { "List" } }
            }
            route("/login") {
                get { call.respond(FreeMarkerContent("login.ftl", model = mapOf("origin" to call.request.queryParameters["origin"]))) }

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

                        val origin = call.request.queryParameters["origin"]

                        if (!origin.isNullOrBlank()) {
                            call.respondRedirect(origin)
                            return@post
                        }

                        call.respondRedirect("/")
                    }
                }
            }
        }
    }.start(wait = true)
}

data class UserSession(val name: String) : Principal

login.ftl:

<html>
<body>
    <form action = "/login?origin=${origin}" method = "post">
        <input type = "text" name = "username" value = "jetbrains">
        <input type = "password" name = "password" value = "foobar">
        <input type = "submit">
    </form>
</body>
</html>

Другие вопросы по теме