更新 token 刷新
新增 token 刷新功能,包括 API 接口和拦截器逻辑。
This commit is contained in:
@@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user