Skip to content

Commit

Permalink
[FEAT] #339 Interceptor에서 액세스, 리프레시 토큰 관리 작업 구현
Browse files Browse the repository at this point in the history
- 액세스 토큰 만료 됐을 때의 처리
- 리프레시 토큰 만료 됐을 때의 처리
  • Loading branch information
sxunea committed Mar 14, 2024
1 parent cefbe31 commit a2d3c2b
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 24 deletions.

This file was deleted.

135 changes: 135 additions & 0 deletions app/src/main/java/com/runnect/runnect/data/service/AuthInterceptor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.runnect.runnect.data.service

import com.runnect.runnect.application.ApplicationClass
import com.runnect.runnect.application.PreferenceManager
import com.runnect.runnect.data.dto.response.ResponseGetRefreshToken
import com.runnect.runnect.data.dto.response.base.BaseResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import timber.log.Timber
import javax.inject.Inject

class AuthInterceptor @Inject constructor(
private val json: Json
) : Interceptor {
// access Header 에 보내고 이때 401(토큰 만료) 뜨면 액세스 재발급 요청
// 재발급 성공 : 저장
// 재발급 실패 : 재 로그인 토스트 메시지 띄우고 preference 초기화 한 후 로그인 화면 이동
override fun intercept(chain: Interceptor.Chain): Response {
runBlocking { Timber.e("AccessToken : ${getAccessToken()}, RefreshToken : ${getRefreshToken()}") }
val originalRequest = chain.request()

val headerRequest = originalRequest.newAuthTokenBuilder()
.build()

val response = headerRequest.let { chain.proceed(it) }

when (response.code) {
CODE_TOKEN_EXPIRED -> {
try {
Timber.e("Access Token Expired: getNewAccessToken")
response.close()
return handleTokenExpired(chain, originalRequest, headerRequest)
} catch (t: Throwable) {
Timber.e("Exception: ${t.message}")
}
}
}
return response
}

private fun Request.newAuthTokenBuilder() =
runBlocking(Dispatchers.IO) {
val accessToken = getAccessToken()
val refreshToken = getRefreshToken()
newBuilder().apply {
addHeader(ACCESS_TOKEN, accessToken)
addHeader(REFRESH_TOKEN, refreshToken)
}
}


private fun getAccessToken(): String {
return PreferenceManager.getString(
ApplicationClass.appContext,
TOKEN_KEY_ACCESS
)!!
}

private fun getRefreshToken(): String {
return PreferenceManager.getString(
ApplicationClass.appContext,
TOKEN_KEY_REFRESH
)!!
}

private fun handleTokenExpired(
chain: Interceptor.Chain,
originalRequest: Request,
headerRequest: Request
): Response {
val refreshTokenResponse = getRefreshToken(originalRequest, chain)
return if (refreshTokenResponse.isSuccessful) {
handleGetRefreshTokenSuccess(refreshTokenResponse, originalRequest, chain)
} else {
handleGetRefreshTokenFailure(refreshTokenResponse, headerRequest, chain)
}
}

private fun getRefreshToken(originalRequest: Request, chain: Interceptor.Chain): Response {
val baseUrl = ApplicationClass.getBaseUrl()
val refreshToken = getRefreshToken()
val refreshTokenRequest = originalRequest.newBuilder().post("".toRequestBody())
.url("$baseUrl/api/auth/getNewToken")
.addHeader(REFRESH_TOKEN, refreshToken)
.build()

return chain.proceed(refreshTokenRequest)
}

private fun handleGetRefreshTokenSuccess(
refreshTokenResponse: Response,
originalRequest: Request,
chain: Interceptor.Chain
): Response {
refreshTokenResponse.use { response ->
val responseToken = json.decodeFromString<BaseResponse<ResponseGetRefreshToken>>(
response.body?.string().orEmpty()
)
responseToken.data?.data?.let {
Timber.e("New Refresh Token Success: ${it.refreshToken}")
}
}

val newRequest = originalRequest.newAuthTokenBuilder().build()
return chain.proceed(newRequest)
}

private fun handleGetRefreshTokenFailure(
refreshTokenResponse: Response,
headerRequest: Request,
chain: Interceptor.Chain
): Response {
Timber.e("New Refresh Token Failure: ${refreshTokenResponse.code}")
return chain.proceed(headerRequest)
}


companion object {
private const val ACCESS_TOKEN = "accessToken"
private const val CODE_TOKEN_EXPIRED = 401
private const val REFRESH_TOKEN = "refreshToken"

const val TOKEN_KEY_ACCESS = "access"
const val TOKEN_KEY_REFRESH = "refresh"
const val HEADER_TOKEN_INFO_ACCESS = "accessToken"
const val HEADER_TOKEN_INFO_REFRESH = "refreshToken"
}

}

0 comments on commit a2d3c2b

Please sign in to comment.