更新 token 刷新

新增 token 刷新功能,包括 API 接口和拦截器逻辑。
This commit is contained in:
2024-08-31 23:49:15 +08:00
parent 98430f3282
commit 091926a3c1
6 changed files with 66 additions and 25 deletions

View File

@@ -90,5 +90,6 @@ dependencies {
implementation("com.squareup.retrofit2:converter-gson:2.11.0") implementation("com.squareup.retrofit2:converter-gson:2.11.0")
implementation("androidx.credentials:credentials:1.2.2") implementation("androidx.credentials:credentials:1.2.2")
implementation("androidx.credentials:credentials-play-services-auth:1.2.2") implementation("androidx.credentials:credentials-play-services-auth:1.2.2")
implementation("com.auth0.android:jwtdecode:2.0.2")
} }

View File

@@ -2,6 +2,7 @@ package com.aiosman.riderpro
object ConstVars { object ConstVars {
// api 地址 // api 地址
// const val BASE_SERVER = "http://192.168.31.250:8088" // const val BASE_SERVER = "http://192.168.31.190:8088"
// const val BASE_SERVER = "http://192.168.31.251:8088"
const val BASE_SERVER = "https://8.137.22.101:8088" const val BASE_SERVER = "https://8.137.22.101:8088"
} }

View File

@@ -4,6 +4,9 @@ import android.icu.text.SimpleDateFormat
import android.icu.util.TimeZone import android.icu.util.TimeZone
import com.aiosman.riderpro.AppStore import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.ConstVars import com.aiosman.riderpro.ConstVars
import com.aiosman.riderpro.data.ServiceException
import com.auth0.android.jwt.JWT
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Response import okhttp3.Response
@@ -16,7 +19,9 @@ import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager import javax.net.ssl.X509TrustManager
fun getUnsafeOkHttpClient(): OkHttpClient { fun getUnsafeOkHttpClient(
authInterceptor: AuthInterceptor? = null
): OkHttpClient {
return try { return try {
// Create a trust manager that does not validate certificate chains // Create a trust manager that does not validate certificate chains
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager { val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
@@ -46,7 +51,11 @@ fun getUnsafeOkHttpClient(): OkHttpClient {
OkHttpClient.Builder() OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager) .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true } .hostnameVerifier { _, _ -> true }
.addInterceptor(AuthInterceptor()) .apply {
authInterceptor?.let {
addInterceptor(it)
}
}
.build() .build()
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException(e) throw RuntimeException(e)
@@ -56,8 +65,42 @@ fun getUnsafeOkHttpClient(): OkHttpClient {
class AuthInterceptor() : Interceptor { class AuthInterceptor() : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
val requestBuilder = chain.request().newBuilder() val requestBuilder = chain.request().newBuilder()
val token = AppStore.token
token?.let {
val jwt = JWT(token)
val expiresAt = jwt.expiresAt?.time?.minus(3000)
val currentTime = System.currentTimeMillis()
val isExpired = expiresAt != null && currentTime > expiresAt
if (isExpired) {
runBlocking {
val newToken = refreshToken()
if (newToken != null) {
AppStore.token = newToken
}
}
}
}
requestBuilder.addHeader("Authorization", "Bearer ${AppStore.token}") requestBuilder.addHeader("Authorization", "Bearer ${AppStore.token}")
return chain.proceed(requestBuilder.build())
val response = chain.proceed(requestBuilder.build())
return response
}
private suspend fun refreshToken(): String? {
val client = Retrofit.Builder()
.baseUrl(ApiClient.RETROFIT_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(getUnsafeOkHttpClient())
.build()
.create(RiderProAPI::class.java)
val resp = client.refreshToken(AppStore.token ?: "")
val newToken = resp.body()?.token
if (newToken != null) {
AppStore.token = newToken
}
return newToken
} }
} }
@@ -67,7 +110,7 @@ object ApiClient {
const val RETROFIT_URL = "${BASE_API_URL}/" const val RETROFIT_URL = "${BASE_API_URL}/"
const val TIME_FORMAT = "yyyy-MM-dd HH:mm:ss" const val TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"
private val okHttpClient: OkHttpClient by lazy { private val okHttpClient: OkHttpClient by lazy {
getUnsafeOkHttpClient() getUnsafeOkHttpClient(authInterceptor = AuthInterceptor())
} }
private val retrofit: Retrofit by lazy { private val retrofit: Retrofit by lazy {
Retrofit.Builder() Retrofit.Builder()

View File

@@ -89,6 +89,11 @@ interface RiderProAPI {
@GET("auth/token") @GET("auth/token")
suspend fun checkToken(): Response<ValidateTokenResult> suspend fun checkToken(): Response<ValidateTokenResult>
@GET("auth/refresh_token")
suspend fun refreshToken(
@Query("token") token: String
): Response<AuthResult>
@GET("posts") @GET("posts")
suspend fun getPosts( suspend fun getPosts(
@Query("page") page: Int = 1, @Query("page") page: Int = 1,

View File

@@ -56,15 +56,15 @@ fun CustomAsyncImage(
contentScale: ContentScale = ContentScale.Crop contentScale: ContentScale = ContentScale.Crop
) { ) {
val imageLoader = getImageLoader(context) val imageLoader = getImageLoader(context)
val blurBitmap = remember(blurHash) { // val blurBitmap = remember(blurHash) {
blurHash?.let { // blurHash?.let {
BlurHashDecoder.decode( // BlurHashDecoder.decode(
blurHash = it, // blurHash = it,
width = DEFAULT_HASHED_BITMAP_WIDTH, // width = DEFAULT_HASHED_BITMAP_WIDTH,
height = DEFAULT_HASHED_BITMAP_HEIGHT // height = DEFAULT_HASHED_BITMAP_HEIGHT
) // )
} // }
} // }
// var bitmap by remember(imageUrl) { mutableStateOf<Bitmap?>(null) } // var bitmap by remember(imageUrl) { mutableStateOf<Bitmap?>(null) }
// //
@@ -86,16 +86,6 @@ fun CustomAsyncImage(
model = ImageRequest.Builder(context) model = ImageRequest.Builder(context)
.data(imageUrl) .data(imageUrl)
.crossfade(200) .crossfade(200)
.apply {
if (placeholderRes != null) {
placeholder(placeholderRes)
return@apply
}
if (blurBitmap != null) {
placeholder(blurBitmap.toDrawable(context.resources))
}
}
.build(), .build(),
contentDescription = contentDescription, contentDescription = contentDescription,
modifier = modifier, modifier = modifier,

View File

@@ -5,6 +5,7 @@ import coil.ImageLoader
import coil.disk.DiskCache import coil.disk.DiskCache
import coil.memory.MemoryCache import coil.memory.MemoryCache
import coil.request.CachePolicy import coil.request.CachePolicy
import com.aiosman.riderpro.data.api.AuthInterceptor
import com.aiosman.riderpro.data.api.getUnsafeOkHttpClient import com.aiosman.riderpro.data.api.getUnsafeOkHttpClient
import java.util.Date import java.util.Date
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@@ -18,7 +19,7 @@ object Utils {
} }
fun getImageLoader(context: Context): ImageLoader { fun getImageLoader(context: Context): ImageLoader {
val okHttpClient = getUnsafeOkHttpClient() val okHttpClient = getUnsafeOkHttpClient(authInterceptor = AuthInterceptor())
return ImageLoader.Builder(context) return ImageLoader.Builder(context)
.okHttpClient(okHttpClient) .okHttpClient(okHttpClient)
.memoryCachePolicy(CachePolicy.ENABLED) .memoryCachePolicy(CachePolicy.ENABLED)