Ktor: Как проверить аутентификацию внутри обработчика маршрута? - PullRequest
0 голосов
/ 05 июня 2018

Я использую ktor v0.9.2 и хочу отправлять разное содержимое для одного и того же маршрута, основываясь на том, аутентифицирован ли пользователь или нет.

Проблема в том, что я невозможность доступа к принципалу вне блока authenticate { }.

Моя установка выглядит следующим образом:

data class User(
    val userId: Int
) : io.ktor.auth.Principal

fun Application.myApp() {
    install(Authentication) {
        jwt {
            verifier(JwtConfig.verifier)
            validate { credential ->
                val userId = credential.payload.getClaim("userId").asInt()
                when {
                    userId > 0 -> User(userId)
                    else -> null
                }
            }
        }
    }
    install(DefaultHeaders)
    install(CallLogging)
    install(ContentNegotiation) {
        jackson { }
    }
    install(Routing) {
        authenticate {
            get("/protected") {
                // This works fine!!
                val user = call.authentication.principal<User>()
                call.respond(user)
            }
        }

        get("/") {
            val user = call.authentication.principal<User>() // -> User is always null here
            if (user == null) {
                call.respondText("Not Logged User")
            } else {
                call.respondText("Logged User")
            }
        }
    }
}

Маршрут /protected работает нормально, но на маршруте /принципал всегда нулевой.Я думаю, что это что-то вроде конвейера, но я немного растерялся.Может ли кто-нибудь дать некоторые идеи?Спасибо!

1 Ответ

0 голосов
/ 06 июня 2018

Какую версию ktor вы используете?Можете ли вы показать нам свои настройки аутентификации?

У вас должно быть что-то вроде этого (0.9.2):

install(Authentication) {
        jwt {
            verifier(JwtConfig.verifier)
            realm = JwtConfig.realm
            validate {
                val email = it.payload.getClaim("email").toString()
                userRepository.findUser(email)?.let { user ->
                    val token = JwtConfig.makeToken(user)
                    user.copy(token = token)
                }
            }
        }

}

Если процесс аутентификации успешен, пользователь будет доступен через принципала.

Вот обновленный код для 0.9.3.Начиная с теста для проверки поведения.Просто добавьте флаг optional.

class KtorTest {

    @Test fun server() {
        withTestApplication({ myApp() }) {
            val userId = 918354853
            val token = JwtConfig.makeToken(User(userId))
            // The protected route
            handleRequest {
                uri = "/protected"
                addHeader("Authorization", "Bearer $token")
            }.let {
                it.requestHandled shouldBe true
                it.response.content.shouldNotBeNullOrBlank() shouldContain userId.toString()
            }

            // Optional route without token
            handleRequest {}.let {
                it.requestHandled shouldBe true
                it.response.content.shouldNotBeNullOrBlank() shouldBeEqualTo "Not Logged User"
            }

            // Optional route with token
            handleRequest {
                addHeader("Authorization", "Bearer $token")
            }.let {
                it.requestHandled shouldBe true
                it.response.content.shouldNotBeNullOrBlank() shouldBeEqualTo "Logged User"
            }
        }
    }

}

data class User(val userId: Int) : Principal

fun Application.myApp() {
    install(Authentication) {
        jwt {
            verifier(JwtConfig.verifier)
            validate { credential ->
                val userId = credential.payload.getClaim("userId").asInt()
                when {
                    userId > 0 -> User(userId)
                    else -> null
                }
            }
        }
    }
    install(DefaultHeaders)
    install(CallLogging)
    install(ContentNegotiation) { jackson { } }
    install(Routing) {
        authenticate {
            get("/protected") {
                // This works fine!!
                val user = call.authentication.principal<User>()!!
                call.respond(user)
            }
        }

        authenticate(optional = true) {
            get("/") {
                val user = call.authentication.principal<User>() // -> User is always null here
                if (user == null) {
                    call.respondText("Not Logged User")
                } else {
                    call.respondText("Logged User")
                }
            }
        }
    }
}
...