Skip to content

Ktor 服务器中的表单认证

必需依赖项: io.ktor:ktor-server-auth

代码示例: auth-form-html-dsl, auth-form-session

Native 服务器
Ktor 支持 Kotlin/Native,并允许您在没有额外运行时或虚拟机的情况下运行服务器。
支持: ✅

表单认证使用 Web 表单 来收集凭证信息并认证用户。 要在 Ktor 中创建 Web 表单,您可以使用 HTML DSL 或选择 JVM 模板引擎,例如 FreeMarker、Velocity 等。

鉴于在使用表单认证时,用户名和密码以明文形式传递,您需要使用 HTTPS/TLS 来保护敏感信息。

添加依赖项

要启用 form 认证,您需要将 ktor-server-auth 构件包含到构建脚本中:

Kotlin
Groovy
XML

表单认证流程

表单认证流程可能如下所示:

  1. 未认证的客户端向服务器应用程序中的特定 路由 发出请求。

  2. 服务器返回一个 HTML 页面,该页面至少包含一个基于 HTML 的 Web 表单,提示用户输入用户名和密码。

    Ktor 允许您使用 Kotlin DSL 构建表单,或者您可以选择各种 JVM 模板引擎,例如 FreeMarker、Velocity 等。

  3. 当用户提交用户名和密码时,客户端会向服务器发出包含 Web 表单数据(其中包括用户名和密码)的请求。

    kotlin
    POST http://localhost:8080/login
    Content-Type: application/x-www-form-urlencoded
    
    username=jetbrains&password=foobar

    在 Ktor 中,您需要指定用于获取用户名和密码的参数名。

  4. 服务器检测客户端发送的凭证,并响应请求的内容。

安装 form 认证

要安装 form 认证提供者,请在 install 代码块中调用 form 函数:

kotlin
import io.ktor.server.application.*
import io.ktor.server.auth.*
// ...
install(Authentication) {
    form {
        // 配置 form 认证
    }
}

您可以可选地指定一个提供者名称,该名称可用于认证指定路由

配置 form 认证

步骤 1: 配置 form 提供者

form 认证提供者通过 FormAuthenticationProvider.Config 类暴露其设置。在下面的示例中,指定了以下设置:

  • userParamNamepasswordParamName 属性指定了用于获取用户名和密码的参数名。
  • validate 函数检测用户名和密码。 validate 函数检测 UserPasswordCredential,并在成功认证的情况下返回 UserIdPrincipal,如果认证失败则返回 null
  • challenge 函数指定了认证失败时执行的操作。例如,您可以重定向回登录页或发送 UnauthorizedResponse
kotlin
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,并获取认证用户的名称。

kotlin
routing {
    authenticate("auth-form") {
        post("/login") {
            call.respondText("Hello, ${call.principal<UserIdPrincipal>()?.name}!")
        }
    }
}

您可以使用 Session 认证 来存储已登录用户的 ID。 例如,当用户首次使用 Web 表单登录时,您可以将用户名保存到 cookie session 中,并在后续请求中使用 session 提供者授权此用户。