Ktor 서버의 폼 기반 인증
필수 의존성: io.ktor:ktor-server-auth
코드 예제: auth-form-html-dsl, auth-form-session
폼 기반 인증(Form-based authentication)은 웹 폼을 사용하여 자격 증명(credential) 정보를 수집하고 사용자를 인증합니다. Ktor에서 웹 폼을 만들려면 HTML DSL을 사용하거나 FreeMarker, Velocity 등과 같은 JVM 템플릿 엔진 중에서 선택할 수 있습니다.
폼 기반 인증을 사용할 때는 사용자 이름과 비밀번호가 일반 텍스트(clear text)로 전달되므로, 민감한 정보를 보호하기 위해 HTTPS/TLS를 사용해야 합니다.
의존성 추가
form 인증을 활성화하려면 빌드 스크립트에 ktor-server-auth 아티팩트를 포함해야 합니다.
폼 기반 인증 흐름
폼 기반 인증 흐름은 다음과 같습니다.
인증되지 않은 클라이언트가 서버 애플리케이션의 특정 라우트(route)에 요청을 보냅니다.
서버는 사용자에게 사용자 이름과 비밀번호를 입력하도록 요청하는 최소 하나 이상의 HTML 기반 웹 폼으로 구성된 HTML 페이지를 반환합니다.
Ktor를 사용하면 Kotlin DSL을 사용하여 폼을 작성하거나, FreeMarker, Velocity 등 다양한 JVM 템플릿 엔진 중에서 선택할 수 있습니다.
사용자가 사용자 이름과 비밀번호를 제출하면, 클라이언트는 웹 폼 데이터(사용자 이름과 비밀번호 포함)가 포함된 요청을 서버에 보냅니다.
kotlinPOST http://localhost:8080/login Content-Type: application/x-www-form-urlencoded username=jetbrains&password=foobarKtor에서는 사용자 이름과 비밀번호를 가져오는 데 사용되는 매개변수 이름을 지정해야 합니다.
서버는 클라이언트가 보낸 자격 증명을 검증하고 요청된 콘텐츠로 응답합니다.
폼 인증 설치
form 인증 공급자(provider)를 설치하려면 install 블록 내에서 form 함수를 호출하세요.
import io.ktor.server.application.*
import io.ktor.server.auth.*
// ...
install(Authentication) {
form {
// 폼 인증 구성
}
}필요에 따라 특정 라우트를 인증하는 데 사용할 수 있는 공급자 이름을 지정할 수 있습니다.
폼 인증 구성
1단계: 폼 공급자 구성
form 인증 공급자는 FormAuthenticationProvider.Config 클래스를 통해 설정을 노출합니다. 아래 예제에서는 다음과 같은 설정이 지정되었습니다.
userParamName및passwordParamName속성은 사용자 이름과 비밀번호를 가져오는 데 사용되는 매개변수 이름을 지정합니다.validate함수는 사용자 이름과 비밀번호를 검증합니다.validate함수는UserPasswordCredential을 확인하고 인증에 성공하면UserIdPrincipal을 반환하며, 실패하면null을 반환합니다.challenge함수는 인증에 실패할 경우 수행할 동작을 지정합니다. 예를 들어, 로그인 페이지로 리다이렉트하거나 UnauthorizedResponse를 보낼 수 있습니다.
install(Authentication) {
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")
}
}
}
basic인증과 마찬가지로, 사용자 이름과 비밀번호 해시를 보관하는 인메모리 테이블에 저장된 사용자를 검증하기 위해 UserHashedTableAuth를 사용할 수도 있습니다.
2단계: 특정 리소스 보호
form 공급자를 구성한 후에는 데이터가 전송될 post 라우트를 정의해야 합니다. 그런 다음 이 라우트를 authenticate 함수 내부에 추가합니다. 인증에 성공하면 라우트 핸들러 내부에서 call.principal 함수를 사용하여 인증된 UserIdPrincipal을 검색하고 인증된 사용자의 이름을 가져올 수 있습니다.
routing {
authenticate("auth-form") {
post("/login") {
call.respondText("Hello, ${call.principal<UserIdPrincipal>()?.name}!")
}
}
}로그인한 사용자의 ID를 저장하기 위해 세션 인증(Session authentication)을 사용할 수 있습니다. 예를 들어, 사용자가 처음 웹 폼을 사용하여 로그인할 때 사용자 이름을 쿠키 세션에 저장하고, 이후 요청에서는 session 공급자를 사용하여 이 사용자를 승인할 수 있습니다.
