【问题标题】:Refresh auth token in Ktor for iOS Http client在 Ktor 中为 iOS Http 客户端刷新身份验证令牌
【发布时间】:2021-12-16 09:11:22
【问题描述】:

我有一个 KMM 项目,我一直在其中使用 Ktor 进行 API 调用。我有一个要求,如果它们已过期,我需要在刷新令牌的帮助下更新我的访问令牌。基本上我只需要在我的 Ktor 客户端中添加一个身份验证模块。不,我已经检查了所有 Ktor documentation 并在我的 KMM 中添加了 Auth 模块。

现在,当我在我的 http 客户端中添加身份验证模块时,它会成功添加,并且每当我从任何 API 收到 UnAuthorized 用户错误时,它都会调用我的刷新令牌 API。问题是即使它调用了我的刷新令牌 API,但在刷新令牌成功时,它不会调用我从中收到 UnAuthorized 用户错误的其他 API。

它在 Android 中按预期工作,但唯一的问题是在 iOS 客户端中。

预期(在 Android Http 客户端中运行良好):-

  • 调用任何 API -> 如果收到任何UnAuthorized 用户错误调用刷新令牌 API -> onSuccess of refresh token API -> 使用更新的刷新令牌再次调用第一个 API。

我面临的问题:-

  • 调用任何 API -> 如果收到任何 UnAuthorized 用户错误,则调用刷新令牌 API -> onSuccess of refresh token API -> 此步骤不执行任何操作,只会从第一个 API 引发未经授权的用户错误。

HttpClient 适用于 iOS:-

actual class HttpBaseClient {

    actual val tokenClient = HttpClient {
        defaultRequest {
            host = ApiEndPoints.Base.url
            url {
                protocol = URLProtocol.HTTPS
            }
            contentType(ContentType.Application.Json)
            header(CONNECTION, CLOSE)
        }
        install(JsonFeature) {
            val json = kotlinx.serialization.json.Json {
                ignoreUnknownKeys = true
                coerceInputValues = true
            }
            serializer = KotlinxSerializer(json)
        }
    }

    actual val httpClient: HttpClient = HttpClient {
        defaultRequest {
            host = ApiEndPoints.Base.url
            url {
                protocol = URLProtocol.HTTPS
            }
            contentType(ContentType.Application.Json)
            header(CONNECTION, CLOSE)
        }
        // Validate Response
        expectSuccess = false
        // Install Auth
        install(Auth) {
            lateinit var refreshTokenInfo : LoginResponse
            bearer {
                refreshTokens { unauthorizedResponse: HttpResponse ->
                    NSLog("Unauthorized response received")
                    BaseAPIClass().refreshAuthToken().fold(
                        failed = {
                            // On Failed
                            NSLog("Token Failed"). // No Callback received here
                        },
                        succeeded = { response ->
                            refreshTokenInfo = response
                            NSLog("Token Updated") // No Callback received here even when API is success
                        }
                    )
                    BearerTokens(
                        accessToken = refreshTokenInfo.accessToken ?: "",
                        refreshToken = refreshTokenInfo.refreshToken ?: ""
                    )
                }
            }
        }
        // JSON Deserializer
        install(JsonFeature) {
            val json = kotlinx.serialization.json.Json {
                ignoreUnknownKeys = true
                coerceInputValues = true
            }
            serializer = KotlinxSerializer(json)
        }

Android 客户端(几乎相同):-

actual class HttpBaseClient {

    actual val tokenClient = HttpClient {
        defaultRequest {
            host = ApiEndPoints.Base.url
            url {
                protocol = URLProtocol.HTTPS
            }
            contentType(ContentType.Application.Json)
            header(CONNECTION, CLOSE)
        }
        install(JsonFeature) {
            val json = kotlinx.serialization.json.Json {
                ignoreUnknownKeys = true
                coerceInputValues = true
            }
            serializer = KotlinxSerializer(json)
        }
        install(Logging) {
            logger = Logger.DEFAULT
            level = LogLevel.ALL
        }
    }

    actual val httpClient: HttpClient = HttpClient {
        defaultRequest {
            host = ApiEndPoints.Base.url
            url {
                protocol = URLProtocol.HTTPS
            }
            contentType(ContentType.Application.Json)
            header(CONNECTION, CLOSE)
        }
        // Validate Response
        expectSuccess = false
        //Authentication
        install(Auth) {
            lateinit var refreshTokenInfo : LoginResponse
            bearer {
                refreshTokens { unauthorizedResponse: HttpResponse ->
                    BaseAPIClass().refreshAuthToken().fold(
                        failed = {
                            // On Failed
                        },
                        succeeded = { response ->
                            refreshTokenInfo = response
                        }
                    )
                    BearerTokens(
                        accessToken = refreshTokenInfo.accessToken ?: "",
                        refreshToken = refreshTokenInfo.refreshToken ?: ""
                    )
                }
            }
        }

Ktor 版本:- 1.6.2(在阅读 this issue 后也尝试了 1.6.4,但没有用)

【问题讨论】:

  • 我不知道如何解决你的问题,但首先你不需要为每个平台创建实现HttpBaseClient。您可以将代码从这些类之一移动到公共模块中,它应该可以正常工作。重复代码可能会导致很多问题,KMM 旨在尽可能减少重复。
  • @PhilipDukhov 我知道我可以为这两个平台拥有一个客户端,但由于某种原因,我创建的两个平台都不同。无论如何,我已经为这两个平台创建了一个客户端,但对我来说仍然没有任何区别。它适用于 android,但不适用于 iOS。

标签: ios kotlin-multiplatform ktor kmm ktor-client


【解决方案1】:

我得到了这个工作,只是错误出现在这段代码中:-

succeeded = { response ->
                        refreshTokenInfo = response
                        NSLog("Token Updated") // No Callback received here even when API is success
                    }

我不知道为什么,但是将响应分配给我的lateinit var refreshTokenInfo 是这里的主要问题。我删除了它并将我的代码更新为

refreshTokens { unauthorizedResponse: HttpResponse ->
                BaseAPIClass().refreshAuthToken().fold(
                    failed = {
                        // On Failed
                        return@refreshTokens BearerTokens(
                            accessToken = "",
                            refreshToken = ""
                        )
                    },
                    succeeded = { response ->
                      return@refreshTokens BearerTokens(
                            accessToken = response.accessToken ?: "",
                            refreshToken = response.refreshToken ?: ""
                        )
                    }
                )
            }

这行得通。

我也提过这个问题here你可以看详情。

【讨论】:

    猜你喜欢
    • 2017-12-29
    • 2017-11-08
    • 2014-04-16
    • 2021-07-22
    • 1970-01-01
    • 2019-05-23
    • 2016-04-04
    • 2020-01-16
    • 2013-08-19
    相关资源
    最近更新 更多