Ktor中的表单身份验证

我是KotlinKtor尝试查看认证部分的Ktor ,所以我得到了下面的代码。

路线“/”和“/再见”工作正常,但路线“登录”给予空白页!

 package blog import kotlinx.html.* import kotlinx.html.stream.* // for createHTML import org.jetbrains.ktor.application.* import org.jetbrains.ktor.auth.* import org.jetbrains.ktor.features.* import org.jetbrains.ktor.http.* import org.jetbrains.ktor.response.* import org.jetbrains.ktor.routing.* import org.jetbrains.ktor.request.* // for request.uri import org.jetbrains.ktor.html.* import org.jetbrains.ktor.pipeline.* import org.jetbrains.ktor.host.* // for embededServer import org.jetbrains.ktor.netty.* // for Netty fun main(args: Array<String>) { embeddedServer(Netty, 8080, watchPaths = listOf("BlogAppKt"), module = Application::module).start() } fun Application.module() { install(DefaultHeaders) install(CallLogging) intercept(ApplicationCallPipeline.Call) { if (call.request.uri == "/hi") call.respondText("Test String") } install(Routing) { get("/") { call.respondText("""Hello, world!<br><a href="/bye">Say bye?</a>""", ContentType.Text.Html) } get("/bye") { call.respondText("""Good bye! <br><a href="/login">Login?</a> """, ContentType.Text.Html) } route("/login") { authentication { formAuthentication { up: UserPasswordCredential -> when { up.password == "ppp" -> UserIdPrincipal(up.name) else -> null } } } handle { val principal = call.authentication.principal<UserIdPrincipal>() if (principal != null) { call.respondText("Hello, ${principal.name}") } else { val html = createHTML().html { body { form(action = "/login", encType = FormEncType.applicationXWwwFormUrlEncoded, method = FormMethod.post) { p { +"user:" textInput(name = "user") { value = principal?.name ?: "" } } p { +"password:" passwordInput(name = "pass") } p { submitInput() { value = "Login" } } } } } call.respondText(html, ContentType.Text.Html) } } } } } 

当我禁用下面的认证部分时,路由“/ login”显示了所需的形式,这意味着错误最有可能在这部分或调用它的方式? 我猜。

  authentication { formAuthentication { up: UserPasswordCredential -> when { up.password == "ppp" -> UserIdPrincipal(up.name) else -> null } } } 

你不是简单的给一个空白页面,你会得到一个401 (UNAUTHORIZED)的HTTP状态代码。 这是因为formAuthentication有四个参数,其中三个是默认值。 你只实现了最后一个( validate ,没有默认):

 userParamName: String = "user", passwordParamName: String = "password", challenge: FormAuthChallenge = FormAuthChallenge.Unauthorized, validate: (UserPasswordCredential) -> Principal? 

每当你到达/login路线没有正确的凭证已经到位,你会得到默认的challenge ,这是FormAuthChallenge.Unauthorized ,这是一个401响应。

而不是使用默认的challenge ,你可以使用FormAuthChallenge.Redirect 。 一个简短的例子,需要两个路线:

 get("/login") { val html = """ <form action="/authenticate" enctype="..." REST OF YOUR LOGIN FORM </form> """ call.respondText(html, ContentType.Text.Html) } route("/authenticate") { authentication { formAuthentication(challenge = FormAuthChallenge.Redirect({ _, _ -> "/login" })) { credential: UserPasswordCredential -> when { credential.password == "secret" -> UserIdPrincipal(credential.name) else -> null } } } handle { val principal = call.authentication.principal<UserIdPrincipal>() val html = "Hello, ${principal?.name}" call.respondText(html, ContentType.Text.Html) } } 

UPDATE

如果上述情况不能很好地工作,那么请明确地定义userid-parameterpassword-parameter因为它们以POSTform出现,如下所示:

  authentication { formAuthentication("user", "pass", challenge = FormAuthChallenge.Redirect({ _, _ -> "/login" })){ credential: UserPasswordCredential -> when { credential.password == "secret" -> UserIdPrincipal(credential.name) else -> null } } }