【问题标题】:Ktor client Auth feature does not sending Authorization headerKtor 客户端身份验证功能不发送授权标头
【发布时间】:2020-08-05 07:38:01
【问题描述】:

我正在尝试在 Kotlin/MPP(多平台)项目中使用 ktor client 并在 JVM 目标功能上使用 basic authentication 似乎没有效果。

这是一个重现的例子:

import io.ktor.client.HttpClient
import io.ktor.client.features.ResponseException
import io.ktor.client.features.auth.Auth
import io.ktor.client.features.auth.providers.basic
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.serializer.KotlinxSerializer
import io.ktor.client.features.logging.DEFAULT
import io.ktor.client.features.logging.LogLevel
import io.ktor.client.features.logging.Logger
import io.ktor.client.features.logging.Logging
import io.ktor.client.request.get
import io.ktor.client.request.header
import kotlinx.coroutines.runBlocking
import java.util.*

fun main() = runBlocking {
    val client = HttpClient {
        install(Logging) {
            logger = Logger.DEFAULT
            level = LogLevel.HEADERS
        }
        install(JsonFeature) {
            serializer = KotlinxSerializer()
        }
        install(Auth) {
            basic {
                username = "user"
                password = "pass"
            }
        }
    }
    val url = "https://en.wikipedia.org/wiki/Main_Page"

    val failing = try {
        client.get<String>(url)
    } catch (e: ResponseException) {
        "failed"
    }

    val succeeding = try {
        client.get<String>(url) {
            header("Authorization", "Basic ${Base64.getEncoder().encodeToString("user:pass".toByteArray())}")
        }
    } catch (e: ResponseException) {
        "failed"
    }
}

观察

从记录器输出中,您可以看到客户端没有发送Authorization 标头,但是当我手动提供此类标头时我没有遇到任何问题:

第一个请求(失败示例:)

[main] INFO io.ktor.client.HttpClient - REQUEST: https://en.wikipedia.org/wiki/Main_Page
[main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
[main] INFO io.ktor.client.HttpClient - COMMON HEADERS
[main] INFO io.ktor.client.HttpClient - -> Accept: application/json
[main] INFO io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
[main] INFO io.ktor.client.HttpClient - CONTENT HEADERS

第二次请求(成功示例:)

[main] INFO io.ktor.client.HttpClient - REQUEST: https://en.wikipedia.org/wiki/Main_Page
[main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
[main] INFO io.ktor.client.HttpClient - COMMON HEADERS
[main] INFO io.ktor.client.HttpClient - -> Authorization: Basic dXNlcjpwYXNz
[main] INFO io.ktor.client.HttpClient - -> Accept: application/json
[main] INFO io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
[main] INFO io.ktor.client.HttpClient - CONTENT HEADERS

环境

  • Kotlin:1.4-M1

Ktor Artifacts 版本 1.3.1:

  • ktor-client-core
  • ktor 客户端日志记录
  • ktor-client-json
  • ktor 客户端序列化
  • ktor-client-auth-basic

我错过了什么吗?

【问题讨论】:

  • 不确定是否是这种情况,但这是一个已修复的错误。尝试使用 ktor 版本 1.3.5-M1
  • 我找不到这样的版本。你能推荐工件的来源吗?
  • 原谅我的记忆,我混淆了协程版本和ktor版本。您应该使用 ktor 版本 1.3.2-1.4-M1。因为它是用新后端编译的。 1.3.1 使用旧后端

标签: kotlin ktor kotlin-multiplatform ktor-client


【解决方案1】:

请添加 sendWithoutRequest = true

https://api.ktor.io/1.3.1/io.ktor.client.features.auth.providers/-basic-auth-config/send-without-request.html

 install(Auth) {
            basic {
                sendWithoutRequest = true
                username = "user"
                password = "pass"
            }
        }

结果:

sending with sendWithoutRequest set to true
[main] INFO io.ktor.client.HttpClient - REQUEST: https://en.wikipedia.org/wiki/Main_Page
[main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
[main] INFO io.ktor.client.HttpClient - COMMON HEADERS
[main] INFO io.ktor.client.HttpClient - -> Authorization: Basic dXNlcjpwYXNz
[main] INFO io.ktor.client.HttpClient - -> Accept: application/json
[main] INFO io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
[main] INFO io.ktor.client.HttpClient - CONTENT HEADERS

说明:

默认情况下,Ktor 会等待服务器响应 401, 未经授权,然后才发送身份验证标头。在你的 例如,wiki 从不响应 401,因为它不是受保护的 资源。因此,需要添加 sendWithoutRequest。如果你 尝试使用一些响应 401 的 url,你会看到 然后 Ktor 将发送第二个请求(在收到 401 之后) 身份验证标头。您可以尝试使用此网址查看 - https://api.sumologic.com/api/v1/collectors.

这是在 sendWithoutRequest 关闭的情况下针对受保护的 api 完成的日志记录,即您的原始输入。如您所见,现在有 2 个请求发出,第一个没有授权标头,然后第二个带有授权标头,在服务器响应 401 之后。

sending with sendWithoutRequest set to false and hitting a protected resource
    [main] INFO io.ktor.client.HttpClient - REQUEST: https://api.sumologic.com/api/v1/collectors
    [main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
    [main] INFO io.ktor.client.HttpClient - COMMON HEADERS
    [main] INFO io.ktor.client.HttpClient - -> Accept: application/json
    [main] INFO io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
    [main] INFO io.ktor.client.HttpClient - CONTENT HEADERS
    [main] INFO io.ktor.client.HttpClient - REQUEST: https://api.sumologic.com/api/v1/collectors
    [main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
    [main] INFO io.ktor.client.HttpClient - COMMON HEADERS
    [main] INFO io.ktor.client.HttpClient - -> Accept: application/json
    [main] INFO io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
    [main] INFO io.ktor.client.HttpClient - -> Authorization: Basic dXNlcjpwYXNz
    [main] INFO io.ktor.client.HttpClient - CONTENT HEADERS

注意:我刚刚看到 Andylamax 的评论说新版本“修复”了它。也许,我不知道,因为我没有尝试过那个新版本。但我想补充一点,这不是 Ktor 独有的东西,至少在这方面不是错误(但也许他们改变了主意?再说一次,我不知道)。事实上,正是我使用 C# 的经验让我怀疑这里发生了什么并找到了答案。 C# 中的 WebRequest 的行为方式相同,您需要将 PreAuthenticate 设置为 true 以立即发送凭据。见这里https://docs.microsoft.com/en-us/dotnet/api/system.net.webrequest.preauthenticate?view=netcore-3.1

【讨论】:

  • 啊哈!我知道我错过了一些东西。也许 Ktor 在线文档应该提到这一点。但奇怪的是,尽管我在问题中使用了 Wikipedia URL,但实际上我确实使用了返回 HTTP 401 的端点,并且 Ktor 在第一次请求时立即抛出 ClientRequestException 而无需授权退出。也许还缺少其他东西(我想知道你是否可以分享更多信息。)无论哪种方式,我都必须在每个请求上携带授权标头,这样你的回答肯定可以解决问题。
猜你喜欢
  • 2022-10-22
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多