From cc0ea522d3334fcdd234343d646f552f50f6b85e Mon Sep 17 00:00:00 2001 From: young Date: Thu, 23 Nov 2023 15:51:46 +0900 Subject: [PATCH 1/2] =?UTF-8?q?#86=20feat=20:=20refreshTokenRequest=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nibobnebob/data/model/request/RefreshTokenRequest.kt | 5 +++++ .../java/com/avengers/nibobnebob/data/remote/RefreshApi.kt | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 Aos/app/src/main/java/com/avengers/nibobnebob/data/model/request/RefreshTokenRequest.kt diff --git a/Aos/app/src/main/java/com/avengers/nibobnebob/data/model/request/RefreshTokenRequest.kt b/Aos/app/src/main/java/com/avengers/nibobnebob/data/model/request/RefreshTokenRequest.kt new file mode 100644 index 0000000..e250ba6 --- /dev/null +++ b/Aos/app/src/main/java/com/avengers/nibobnebob/data/model/request/RefreshTokenRequest.kt @@ -0,0 +1,5 @@ +package com.avengers.nibobnebob.data.model.request + +data class RefreshTokenRequest( + val refreshToken: String? +) \ No newline at end of file diff --git a/Aos/app/src/main/java/com/avengers/nibobnebob/data/remote/RefreshApi.kt b/Aos/app/src/main/java/com/avengers/nibobnebob/data/remote/RefreshApi.kt index 498cd40..8bcb828 100644 --- a/Aos/app/src/main/java/com/avengers/nibobnebob/data/remote/RefreshApi.kt +++ b/Aos/app/src/main/java/com/avengers/nibobnebob/data/remote/RefreshApi.kt @@ -1,12 +1,14 @@ package com.avengers.nibobnebob.data.remote +import com.avengers.nibobnebob.data.model.request.RefreshTokenRequest import com.avengers.nibobnebob.data.model.response.BaseResponse import com.avengers.nibobnebob.data.model.response.NaverLoginResponse import retrofit2.Response +import retrofit2.http.Body import retrofit2.http.POST interface RefreshApi { - @POST("토큰 갱신 url") - suspend fun refreshToken(refreshToken : String) : Response> + @POST("api/auth/refresh-token") + suspend fun refreshToken(@Body refreshToken: RefreshTokenRequest) : Response> } \ No newline at end of file From 27c15784c1ccc2aad5976b696d9502b98fe3050b Mon Sep 17 00:00:00 2001 From: young Date: Thu, 23 Nov 2023 15:52:05 +0900 Subject: [PATCH 2/2] =?UTF-8?q?#86=20feat=20:=20BearerInterceptor=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aos/.idea/deploymentTargetDropDown.xml | 2 +- .../nibobnebob/app/di/NetworkModule.kt | 18 ++- .../config/AccessTokenInterceptor.kt | 3 +- .../nibobnebob/config/BearerInterceptor.kt | 112 +++++++++++------- 4 files changed, 87 insertions(+), 48 deletions(-) diff --git a/Aos/.idea/deploymentTargetDropDown.xml b/Aos/.idea/deploymentTargetDropDown.xml index a682024..2830ba7 100644 --- a/Aos/.idea/deploymentTargetDropDown.xml +++ b/Aos/.idea/deploymentTargetDropDown.xml @@ -12,6 +12,6 @@ - + \ No newline at end of file diff --git a/Aos/app/src/main/java/com/avengers/nibobnebob/app/di/NetworkModule.kt b/Aos/app/src/main/java/com/avengers/nibobnebob/app/di/NetworkModule.kt index 84c7188..7863d65 100644 --- a/Aos/app/src/main/java/com/avengers/nibobnebob/app/di/NetworkModule.kt +++ b/Aos/app/src/main/java/com/avengers/nibobnebob/app/di/NetworkModule.kt @@ -1,12 +1,15 @@ package com.avengers.nibobnebob.app.di +import android.content.Context import com.avengers.nibobnebob.BuildConfig +import com.avengers.nibobnebob.app.DataStoreManager import com.avengers.nibobnebob.config.AccessTokenInterceptor import com.avengers.nibobnebob.config.BearerInterceptor import com.avengers.nibobnebob.presentation.util.Constants.BASE_URL import dagger.Module import dagger.Provides import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor @@ -23,7 +26,7 @@ object NetworkModule { httpLoggingInterceptor: HttpLoggingInterceptor, accessTokenInterceptor: AccessTokenInterceptor, bearerInterceptor: BearerInterceptor - ) : OkHttpClient { + ): OkHttpClient { return OkHttpClient.Builder() .readTimeout(3000, TimeUnit.MILLISECONDS) @@ -37,10 +40,19 @@ object NetworkModule { @Provides fun provideLoggingInterceptor(): HttpLoggingInterceptor { return HttpLoggingInterceptor().apply { - level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE + level = + if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE } } + @Provides + fun provideAccessTokenInterceptor(dataStoreManager: DataStoreManager): AccessTokenInterceptor = + AccessTokenInterceptor(dataStoreManager) + + @Provides + fun provideBearerInterceptor(dataStoreManager: DataStoreManager): BearerInterceptor = + BearerInterceptor(dataStoreManager) + @Provides fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { @@ -51,5 +63,5 @@ object NetworkModule { .build() } - + } \ No newline at end of file diff --git a/Aos/app/src/main/java/com/avengers/nibobnebob/config/AccessTokenInterceptor.kt b/Aos/app/src/main/java/com/avengers/nibobnebob/config/AccessTokenInterceptor.kt index 3242eb1..3d7f144 100644 --- a/Aos/app/src/main/java/com/avengers/nibobnebob/config/AccessTokenInterceptor.kt +++ b/Aos/app/src/main/java/com/avengers/nibobnebob/config/AccessTokenInterceptor.kt @@ -4,6 +4,7 @@ import android.util.Log import com.avengers.nibobnebob.app.DataStoreManager import com.avengers.nibobnebob.presentation.util.Constants.ACCESS import com.avengers.nibobnebob.presentation.util.Constants.AUTHORIZATION +import com.avengers.nibobnebob.presentation.util.Constants.BEARER import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import okhttp3.Interceptor @@ -24,7 +25,7 @@ class AccessTokenInterceptor @Inject constructor(private val dataStoreManager: D Log.d("토큰 테스트",accessToken.toString()) val builder: Request.Builder = chain.request().newBuilder() accessToken.let { - builder.addHeader(AUTHORIZATION,"$ACCESS $accessToken") + builder.addHeader(AUTHORIZATION,"$BEARER $accessToken") } return chain.proceed(builder.build()) } diff --git a/Aos/app/src/main/java/com/avengers/nibobnebob/config/BearerInterceptor.kt b/Aos/app/src/main/java/com/avengers/nibobnebob/config/BearerInterceptor.kt index 8c20059..47244ec 100644 --- a/Aos/app/src/main/java/com/avengers/nibobnebob/config/BearerInterceptor.kt +++ b/Aos/app/src/main/java/com/avengers/nibobnebob/config/BearerInterceptor.kt @@ -1,62 +1,88 @@ package com.avengers.nibobnebob.config +import com.avengers.nibobnebob.app.DataStoreManager +import com.avengers.nibobnebob.data.model.BaseState +import com.avengers.nibobnebob.data.model.request.RefreshTokenRequest +import com.avengers.nibobnebob.data.model.response.BaseResponse +import com.avengers.nibobnebob.data.model.response.NaverLoginResponse +import com.avengers.nibobnebob.data.model.runRemote +import com.avengers.nibobnebob.data.remote.RefreshApi +import com.avengers.nibobnebob.presentation.util.Constants +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking import okhttp3.Interceptor +import okhttp3.OkHttpClient import okhttp3.Response +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory import java.io.IOException import javax.inject.Inject -class BearerInterceptor @Inject constructor() : Interceptor { +class BearerInterceptor @Inject constructor( + private val dataStoreManager: DataStoreManager +) : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { + val originalRequest = chain.request() val response = chain.proceed(originalRequest) -// runBlocking { -// 로컬에 refreshToken이 있다면 -// sharedPreferences.getString(X_REFRESH_TOKEN, null)?.let { refresh -> -// Log.d(TAG, refresh) -// // refresh API 호출 -// val result = Retrofit.Builder() -// .baseUrl(BASE_DEV_URL) -// .addConverterFactory(GsonConverterFactory.create()) -// .build() -// .create(RefreshAPI::class.java).refreshToken(refresh) -// -// if (result.isSuccessful) { -// Log.d(TAG,"리프래시 성공") -// result.body()?.let { body -> -// Log.d(TAG,body.accessToken) -// // refresh 성공시 로컬에 저장 -// sharedPreferences.edit() -// .putString(X_ACCESS_TOKEN, body.accessToken) -// .putString(X_REFRESH_TOKEN, body.refreshToken) -// .apply() -// -// isRefreshed = true -// accessToken = body.accessToken -// } -// }else{ -// val error = -// Gson().fromJson(result.errorBody()?.string(), ErrorResponse::class.java) -// Log.d(TAG,error.message) -// } -// } -// } -// -// if (isRefreshed) { -// -// // 기존 API 재호출 -// val newRequest = originalRequest.newBuilder() -// .addHeader("Authorization", accessToken) -// .build() -// -// return chain.proceed(newRequest) -// } - // 해당 특정 에러코드가 그대로 내려간다면, 세션 만료 처리 + var newAccessToken: String? = null + + if (response.code == TOKEN_ERROR) { + runBlocking { + val refreshToken = dataStoreManager.getRefreshToken().first() + refreshToken?.let { token -> + when (val result = getNewAccessToken(token)) { + is BaseState.Success -> { + response.close() + newAccessToken = result.data.body.accessToken + newAccessToken?.let { + dataStoreManager.putAccessToken(newAccessToken!!) + } + } + + else -> { + dataStoreManager.deleteAccessToken() + dataStoreManager.deleteRefreshToken() + } + } + } + } + (newAccessToken)?.let { + val newRequest = originalRequest.newBuilder() + .addHeader(AUTHORIZATION, "$BEARER $newAccessToken") + .build() + return chain.proceed(newRequest) + } + } + return response } + + + private suspend fun getNewAccessToken(refreshToken: String?): BaseState> { + val loggingInterceptor = HttpLoggingInterceptor() + loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY + val okHttpClient = OkHttpClient.Builder().addInterceptor(loggingInterceptor).build() + + val retrofit = Retrofit.Builder() + .baseUrl(Constants.BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .client(okHttpClient) + .build() + val api = retrofit.create(RefreshApi::class.java) + return runRemote { api.refreshToken(RefreshTokenRequest(refreshToken)) } + } + + companion object { + const val TOKEN_ERROR = 401 + const val AUTHORIZATION = "Authorization" + const val BEARER = "Bearer" + } }