【问题标题】:Ktor: How to check authentication inside a route handler?Ktor:如何在路由处理程序中检查身份验证?
【发布时间】:2018-11-15 10:08:28
【问题描述】:

我正在使用 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 路由工作正常,但在/ 路由中,主体始终为空。我认为这是一些管道的事情,但我有点迷茫。有人可以提供一些见解吗?谢谢!

【问题讨论】:

    标签: kotlin ktor


    【解决方案1】:

    您使用的是什么版本的 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")
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 对不起,我没有给你足够的细节。我现在已经编辑了我的问题。
    • 所以基本上您正在寻找可选的身份验证?我刚刚联系了 ktor 团队以了解此功能,但似乎它还没有功能。无论如何,您的第二条路线没有获得任何身份验证的原因是它没有包含在任何 authenticate 块中。
    • 我已为 0.9.3 版中提供的新可选身份验证功能添加了代码。
    • 谢谢安德烈亚斯!
    • 这会不会在您每次验证时在用户中创建一个新令牌?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-11
    • 2013-03-13
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 2020-12-17
    • 2013-08-19
    相关资源
    最近更新 更多