Ktorは標準のプラグイン可能なFeatureとして、すぐに使える認証機能をサポートしています。 credentialの読み込みとprincipalの認証のメカニズムをサポートしています。
リクエスト間でログイン情報を保持するためにsession機能とともに使われるケースもあります。
目次:
io.ktor.auth.Authentication
in the artifact io.ktor:ktor-auth:$ktor_version
.
dependencies {
implementation "io.ktor:ktor-auth:$ktor_version"
}
dependencies {
implementation("io.ktor:ktor-auth:$ktor_version")
}
<project>
...
<dependencies>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-auth</artifactId>
<version>${ktor.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
Ktorはcredentialとprincipalという2つの概念を定義しています。
インストールするためには、application.install(Authentication)
を呼び出す必要があります。
applicationに対し直接インストールする必要があり、Route
のような別のApplicationCallPipeline
内では動きません。
Routeの内側でインストールするコードを実行することができますが、適用されるのはapplicationそのものに対してです。
DSLを使うことで、認証プロバイダの設定を可能にします:
install(Authentication) {
basic(name = "myauth1") {
realm = "Ktor Server"
validate { credentials ->
if (credentials.name == credentials.password) {
UserIdPrincipal(credentials.name)
} else {
null
}
}
}
}
1つ以上の認証プロバイダを(名前付きでも名前無しでも)定義した後、routing機能を使って、 定義した認証が適用されるようなrouteのグループを作成できます。
routing {
authenticate("myauth1") {
get("/authenticated/route1") {
// ...
}
get("/other/route2") {
// ...
}
}
get("/") {
// ...
}
}
いくつかの認証プロバイダを適用するために名前を指定することもできますし、あるいは名前を指定せず使うこともできます。
生成されたPrincipal
のインスタンスをhandlerの内側で以下のように取得することができます:
val principal: UserIdPrincipal? = call.authentication.principal<UserIdPrincipal>()
一般的には、生成したPrincipalにマッチする必要がある特定の型を指定する必要があります。 別の型を指定した場合、nullが返ります。
設定された認証が失敗した場合handlerは実行されません(認証メカニズム内でnull
が返ったとき)
指定の認証プロバイダに任意の名前をつけることができますし、あるいは名前の引数を指定しないまたはnullを渡すことで名前をつけないこともできます。
認証プロバイダ名を重複させることはできず、また名前なしのプロバイダは1つだけしか定義できません。
プロバイダの名前を重複させた場合や、2つの未命名のプロバイダがあった場合は、exceptionが投げられます:
java.lang.IllegalArgumentException: Provider with the name `authName` is already registered
要約すると以下のようになります:
install(Authentication) {
basic { // Unamed `basic` provider
// ...
}
form { // Unamed `form` provider (exception, already defined a provider with name = null)
// ...
}
basic("name1") { // "name1" provider
// ...
}
basic("name1") { // "name1" provider (exception, already defined a provider with name = "name1")
// ...
}
}
基準にしたがって認証をスキップさせることもできます。
/**
* Authentication filters specifying if authentication is required for particular [ApplicationCall]
* If there is no filters, authentication is required. If any filter returns true, authentication is not required.
*/
fun AuthenticationProvider.skipWhen(predicate: (ApplicationCall) -> Boolean)
例えば、すでにセッションがある場合にbasic認証をスキップさせるためには、以下のように書けます:
authentication {
basic {
skipWhen { call -> call.sessions.get<UserSession>() != null }
}
}
カスタムの認証を行いたい場合は、Authentication機能のページを参照してください。
認証機能はPipelineにおいてRequestAuthentication
とCheckAuthentication
という2つのステージで定義されています