dm-181
This commit is contained in:
parent
89da510a3f
commit
f71cb04704
1 changed files with 41 additions and 28 deletions
|
|
@ -2,6 +2,7 @@ package com.example.login_v3.data.di
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.example.login_v3.data.api.TecnologiaApi
|
||||
import com.example.login_v3.data.repository.basic.TokenAuthenticator
|
||||
import com.example.login_v3.data.repository.basic.TokenManager
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
|
|
@ -12,7 +13,9 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
|
|
@ -32,39 +35,49 @@ object NetworkModule {
|
|||
.build()
|
||||
}
|
||||
|
||||
// TokenInterceptor
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(tokenManager: TokenManager): OkHttpClient {
|
||||
fun provideTokenInterceptor(tokenManager: TokenManager): Interceptor {
|
||||
return Interceptor { chain ->
|
||||
val originalRequest = chain.request()
|
||||
val path = originalRequest.url.encodedPath
|
||||
|
||||
// 如果是認證相關的 API,直接放行,不附加 Token Header
|
||||
if (path.contains("api/auth/login") ||
|
||||
path.contains("api/auth/register") ||
|
||||
path.contains("api/auth/refresh") ||
|
||||
path.contains("api/health")) {
|
||||
return@Interceptor chain.proceed(originalRequest)
|
||||
}
|
||||
|
||||
// 在背景執行緒中安全地獲取當前 Token
|
||||
val token = runBlocking(Dispatchers.IO) {
|
||||
tokenManager.currentAccessToken.firstOrNull()
|
||||
}
|
||||
|
||||
val requestBuilder = originalRequest.newBuilder()
|
||||
if (!token.isNullOrEmpty()) {
|
||||
requestBuilder.addHeader("Authorization", "Bearer $token")
|
||||
}
|
||||
|
||||
// ⚠️ 注意:這裡不再手動處理 401 logout,純粹放行交給 Authenticator 處理
|
||||
chain.proceed(requestBuilder.build())
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 配置 OkHttpClient,把 Interceptor 和 Authenticator 綁進去
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(
|
||||
tokenInterceptor: Interceptor,
|
||||
tokenAuthenticator: TokenAuthenticator // 👈 注入前面實作好的 Authenticator
|
||||
): OkHttpClient {
|
||||
return OkHttpClient.Builder()
|
||||
.connectTimeout(15, TimeUnit.SECONDS)
|
||||
.readTimeout(15, TimeUnit.SECONDS)
|
||||
.addInterceptor { chain ->
|
||||
// 在 OkHttp 的背景執行緒中安全地進行同步等待
|
||||
val (token, userId) = runBlocking(Dispatchers.IO) {
|
||||
val t = tokenManager.currentAccessToken.first()
|
||||
val id = tokenManager.currentUserId.first()
|
||||
t to id
|
||||
}
|
||||
|
||||
val requestBuilder = chain.request().newBuilder()
|
||||
token?.let {
|
||||
requestBuilder.addHeader("Authorization", "Bearer $it")
|
||||
}
|
||||
|
||||
val response = chain.proceed(requestBuilder.build())
|
||||
|
||||
// 處理 Token 失效 (401)
|
||||
if (response.code == 401) {
|
||||
userId?.let { id ->
|
||||
// 使用 Dispatchers.IO 確保不會卡死主執行緒
|
||||
runBlocking(Dispatchers.IO) {
|
||||
tokenManager.logout(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response
|
||||
}
|
||||
.addInterceptor(tokenInterceptor) // 負責幫一般請求加上 Token
|
||||
.authenticator(tokenAuthenticator) // 負責在 401 時自動刷新 Token
|
||||
.build()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue