Ktor Serverにおけるフォームベース認証
必須の依存関係: io.ktor:ktor-server-auth
コード例: auth-form-html-dsl, auth-form-session
フォームベース認証は、ウェブフォームを使用して資格情報を収集し、ユーザーを認証します。 Ktorでウェブフォームを作成するには、HTML DSLを使用するか、FreeMarkerやVelocityなどのJVMテンプレートエンジンから選択できます。
フォームベース認証を使用する場合、ユーザー名とパスワードはプレーンテキストとして送信されるため、機密情報を保護するためにHTTPS/TLSを使用する必要があります。
依存関係の追加
form認証を有効にするには、ビルドスクリプトにktor-server-authアーティファクトを含める必要があります。
フォームベース認証のフロー
フォームベース認証のフローは以下のようになります。
認証されていないクライアントが、サーバーアプリケーションの特定のルートにリクエストを送信します。
サーバーは、ユーザーにユーザー名とパスワードの入力を求める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認証プロバイダーをインストールするには、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プロバイダーを使用してそのユーザーを認可することができます。
