Skip to content

Ktor Server 中的基于表单的身份验证

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

代码示例auth-form-html-dslauth-form-session

原生服务器
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 身份验证提供者,请在 install 块内调用 form 函数:

kotlin
import io.ktor.server.application.*
import io.ktor.server.auth.*
// ...
install(Authentication) {
    form {
        // 配置表单身份验证
    }
}

您可以选择指定一个提供者名称,该名称可用于对指定路由进行身份验证

配置表单身份验证

第 1 步:配置表单提供者

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}!")
        }
    }
}

您可以使用会话身份验证来存储已登录用户的 ID。 例如,当用户第一次使用 Web 表单登录时,您可以将用户名保存到 Cookie 会话中,并在后续请求中使用 session 提供者授权该用户。