Ktor:如何在路由处理程序中检查身份验证?

时间:2018-06-05 20:15:06

标签: kotlin ktor

我正在使用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 :(得分:0)

您使用的是什么版本的ktor? 你能告诉我们你的auth设置吗?

你应该有这样的东西(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")
                }
            }
        }
    }
}