From 80fa0be8f6ec37a6bf43a928b5e20025c1c03d97 Mon Sep 17 00:00:00 2001 From: penghanyuan Date: Sat, 14 Feb 2026 14:07:21 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Ktor=20=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E8=AE=A4=E8=AF=81=E6=8F=92=E4=BB=B6=E4=BB=A5?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=20API=20=E5=AE=89=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 build.gradle.kts 中新增 Ktor 客户端认证依赖。 - 更新 ApiService 类,使用 Ktor 内置的 Auth 插件实现 Bearer token 自动管理和刷新逻辑,提升 API 调用的安全性和稳定性。 --- app-android/app/build.gradle.kts | 1 + .../com/huaga/life_echo/network/ApiService.kt | 54 ++++++++++++++++--- app-android/gradle/libs.versions.toml | 1 + 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/app-android/app/build.gradle.kts b/app-android/app/build.gradle.kts index ba8cf43..6c771df 100644 --- a/app-android/app/build.gradle.kts +++ b/app-android/app/build.gradle.kts @@ -137,6 +137,7 @@ dependencies { implementation(libs.ktor.client.content.negotiation) implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.ktor.client.logging) + implementation(libs.ktor.client.auth) // Room implementation(libs.androidx.room.runtime) diff --git a/app-android/app/src/main/java/com/huaga/life_echo/network/ApiService.kt b/app-android/app/src/main/java/com/huaga/life_echo/network/ApiService.kt index c93ca55..45400f4 100644 --- a/app-android/app/src/main/java/com/huaga/life_echo/network/ApiService.kt +++ b/app-android/app/src/main/java/com/huaga/life_echo/network/ApiService.kt @@ -1,11 +1,12 @@ package com.huaga.life_echo.network import com.huaga.life_echo.data.auth.TokenManager -import com.huaga.life_echo.network.interceptors.AuthInterceptorPlugin import com.huaga.life_echo.network.models.* import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.engine.android.* +import io.ktor.client.plugins.auth.* +import io.ktor.client.plugins.auth.providers.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* import io.ktor.client.plugins.HttpTimeout @@ -19,8 +20,8 @@ import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive class ApiService( - tokenManager: TokenManager? = null, - authService: AuthService? = null + private val tokenManager: TokenManager? = null, + private val authService: AuthService? = null ) { private val client = HttpClient(Android) { install(ContentNegotiation) { @@ -36,12 +37,49 @@ class ApiService( connectTimeoutMillis = 15_000 // 连接超时 socketTimeoutMillis = 45_000 // 读写超时 } - - // 如果提供了tokenManager和authService,安装认证拦截器 + + // 使用Ktor内置Auth插件:自动添加Bearer token,401时自动刷新并重试 if (tokenManager != null && authService != null) { - install(AuthInterceptorPlugin) { - this.tokenManager = tokenManager - this.authService = authService + install(Auth) { + bearer { + loadTokens { + val access = tokenManager.getAccessToken() + val refresh = tokenManager.getRefreshToken() + if (!access.isNullOrBlank() && !refresh.isNullOrBlank()) { + BearerTokens(access, refresh) + } else null + } + refreshTokens { + val refresh = oldTokens?.refreshToken + ?: tokenManager.getRefreshToken() + if (!refresh.isNullOrBlank()) { + val result = authService.refreshToken(refresh) + result.fold( + onSuccess = { tokenResponse -> + tokenManager.saveTokens( + tokenResponse.access_token, + tokenResponse.refresh_token, + tokenManager.getUserId() ?: "" + ) + BearerTokens( + tokenResponse.access_token, + tokenResponse.refresh_token + ) + }, + onFailure = { + tokenManager.clearTokens() + tokenManager.notifyTokenRefreshFailed() + null + } + ) + } else { + tokenManager.clearTokens() + tokenManager.notifyTokenRefreshFailed() + null + } + } + sendWithoutRequest { true } + } } } } diff --git a/app-android/gradle/libs.versions.toml b/app-android/gradle/libs.versions.toml index fcb0b77..0ec59df 100644 --- a/app-android/gradle/libs.versions.toml +++ b/app-android/gradle/libs.versions.toml @@ -45,6 +45,7 @@ ktor-client-websockets = { group = "io.ktor", name = "ktor-client-websockets", v ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" } ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" } ktor-client-logging = { group = "io.ktor", name = "ktor-client-logging", version.ref = "ktor" } +ktor-client-auth = { group = "io.ktor", name = "ktor-client-auth", version.ref = "ktor" } # Room androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }