Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REFACTOR] 데이터 레이어 다른 계층 참조하지 않도록 코드 분리 #340

Merged
merged 18 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a2d3c2b
[FEAT] #339 Interceptor에서 액세스, 리프레시 토큰 관리 작업 구현
sxunea Mar 14, 2024
b609e6c
[FEAT] #339 액세스 토큰 재발급 성공시, preference에 해당 값 저장
sxunea Mar 14, 2024
8b882b7
[FEAT] #339 리프레시 토큰 또한 만료 / 통신 실패 시 빈 값 preference에 저장
sxunea Mar 14, 2024
123e7e7
[CHORE] #339 주석 추가 및 코드 정리
sxunea Mar 14, 2024
60adff3
[DEL] #339 Authenticator 제거
sxunea Mar 14, 2024
3e8d971
[MOD] #339 레트로핏 모듈에 Interceptor 반영
sxunea Mar 14, 2024
1aebc18
[FEAT] #339 accessToken 빈 문자열이면 토스트메시지와 함께 재로그인 요청
sxunea Mar 14, 2024
2ac7be5
[REFACTOR] #339 non null 단언 연산자 제거
sxunea Mar 14, 2024
0c210d0
[REFACTOR] #339 named argument 적용
sxunea Mar 24, 2024
ead0369
[REFACTOR] #339 interceptor return if로 response처리
sxunea Mar 24, 2024
60bbd81
[REFACTOR] #339 리뷰 간단사항 반영
sxunea Mar 24, 2024
a5eab3d
[ADD] #339 LoginStatus Enum Class 만들어 적용해 토큰 값 따른 로그인 상태 관리
sxunea Mar 24, 2024
b3267c8
[REFACTOR] #339 토큰preferenceManager AuthUtil로 빼서 관리
sxunea Mar 24, 2024
625d913
[MOD] #339 applicationContext 주입
sxunea Mar 24, 2024
e9c245b
[MOD] #339 runBlocking제거
sxunea Mar 27, 2024
0af3516
[REFACTOR] #339 applicationContext -> context로 변경하고, null 안전하게 체크
sxunea Mar 27, 2024
a390166
Merge remote-tracking branch 'origin/develop' into feature/refactor-data
sxunea Apr 24, 2024
7315ecc
[MERGE] #339 충돌 해결
sxunea Apr 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import com.runnect.runnect.R
import com.runnect.runnect.application.ApiMode
import com.runnect.runnect.application.ApplicationClass
import com.runnect.runnect.application.PreferenceManager
import com.runnect.runnect.data.service.TokenAuthenticator
import com.runnect.runnect.presentation.mypage.setting.accountinfo.MySettingAccountInfoFragment
import com.runnect.runnect.util.custom.toast.RunnectToast
import com.runnect.runnect.util.preference.AuthUtil.getAccessToken
import com.runnect.runnect.util.preference.AuthUtil.getNewToken
import com.runnect.runnect.util.preference.AuthUtil.saveToken
import com.runnect.runnect.util.preference.StatusType.LoginStatus
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
Expand All @@ -44,15 +46,15 @@ class RunnectDeveloperActivity : AppCompatActivity(R.layout.activity_runnect_dev

private fun initUserInfo() {
val ctx: Context = context ?: return
val accessToken = PreferenceManager.getString(ctx, TokenAuthenticator.TOKEN_KEY_ACCESS) ?: ""
val refreshToken = PreferenceManager.getString(ctx, TokenAuthenticator.TOKEN_KEY_REFRESH) ?: ""
val accessToken = ctx.getAccessToken()
val refreshToken = ctx.getNewToken()

setPreferenceSummary("dev_pref_key_access_token", accessToken)
setPreferenceSummary("dev_pref_key_refresh_token", refreshToken)
}

private fun initApiMode() {
val ctx:Context = context ?: ApplicationClass.appContext
val ctx: Context = context ?: ApplicationClass.appContext
val currentApi = ApiMode.getCurrentApiMode(ctx)

findPreference<ListPreference>("dev_pref_key_api_mode")?.apply {
Expand All @@ -70,10 +72,11 @@ class RunnectDeveloperActivity : AppCompatActivity(R.layout.activity_runnect_dev

PreferenceManager.apply {
setString(ctx, ApplicationClass.API_MODE, selectItem)
setString(ctx, MySettingAccountInfoFragment.TOKEN_KEY_ACCESS, "none")
setString(ctx, MySettingAccountInfoFragment.TOKEN_KEY_REFRESH, "none")
}

ctx.saveToken(
accessToken = LoginStatus.NONE.value,
refreshToken = LoginStatus.NONE.value
)
destroyApp(ctx)
true
}
Expand All @@ -93,9 +96,15 @@ class RunnectDeveloperActivity : AppCompatActivity(R.layout.activity_runnect_dev
val naviBarHeight = getNaviBarHeight(windowManager)

with(metrics) {
setPreferenceSummary("dev_pref_display_ratio", "$widthPixels x ${heightPixels + statusBarHeight + naviBarHeight}")
setPreferenceSummary(
"dev_pref_display_ratio",
"$widthPixels x ${heightPixels + statusBarHeight + naviBarHeight}"
)
setPreferenceSummary("dev_pref_display_density", "${densityDpi}dp")
setPreferenceSummary("dev_pref_display_resource_bucket", getDeviceResourseBucket(this))
setPreferenceSummary(
"dev_pref_display_resource_bucket",
getDeviceResourseBucket(this)
)
}
}

Expand All @@ -116,7 +125,8 @@ class RunnectDeveloperActivity : AppCompatActivity(R.layout.activity_runnect_dev
private fun getStatusBarHeight(windowManager: WindowManager): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val windowMetrics = windowManager.currentWindowMetrics
val insets = windowMetrics.windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.statusBars())
val insets =
windowMetrics.windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.statusBars())
insets.top
} else {
0
Expand All @@ -126,7 +136,8 @@ class RunnectDeveloperActivity : AppCompatActivity(R.layout.activity_runnect_dev
private fun getNaviBarHeight(windowManager: WindowManager): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val windowMetrics = windowManager.currentWindowMetrics
val insets = windowMetrics.windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars())
val insets =
windowMetrics.windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars())
insets.bottom
} else {
0
Expand Down Expand Up @@ -157,7 +168,8 @@ class RunnectDeveloperActivity : AppCompatActivity(R.layout.activity_runnect_dev

private fun destroyApp(context: Context) {
lifecycleScope.launch(Dispatchers.Main) {
RunnectToast.createToast(context, getString(R.string.dev_mode_require_restart)).show()
RunnectToast.createToast(context, getString(R.string.dev_mode_require_restart))
.show()
delay(3000)

activity?.finishAffinity() //루트액티비티 종료
Expand Down

This file was deleted.

127 changes: 127 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,127 @@
package com.runnect.runnect.data.service

import android.content.Context
import com.runnect.runnect.application.ApplicationClass
import com.runnect.runnect.data.dto.response.ResponseGetRefreshToken
import com.runnect.runnect.data.dto.response.base.BaseResponse
import com.runnect.runnect.util.preference.AuthUtil.getAccessToken
import com.runnect.runnect.util.preference.AuthUtil.getNewToken
import com.runnect.runnect.util.preference.AuthUtil.saveToken
import com.runnect.runnect.util.preference.StatusType.LoginStatus
import dagger.hilt.android.qualifiers.ApplicationContext
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(
@ApplicationContext private val context: Context,
private val json: Json
) : Interceptor {
// access Header 에 보내고 이때 401(토큰 만료) 뜨면 액세스 재발급 요청
// 재발급 성공 : 저장
// 재발급 실패 : 재 로그인 토스트 메시지 띄우고 preference 빈 값 넣고 로그인 화면 이동
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()

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

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

return if (response.code == CODE_TOKEN_EXPIRED) {
try {
Timber.e("Access Token Expired: getNewAccessToken")
response.close()
handleTokenExpired(chain, originalRequest, headerRequest)
} catch (t: Throwable) {
Timber.e("Exception: ${t.message}")
context.saveToken(
accessToken = LoginStatus.EXPIRED.value,
refreshToken = LoginStatus.EXPIRED.value
)
response
}
} else {
response
}
}

private fun Request.newAuthTokenBuilder(): Request.Builder {
val accessToken = context.getAccessToken()
val refreshToken = context.getNewToken()
return newBuilder().apply {
addHeader(ACCESS_TOKEN, accessToken)
addHeader(REFRESH_TOKEN, refreshToken)
}
}


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

private fun getNewToken(originalRequest: Request, chain: Interceptor.Chain): Response {
val baseUrl = ApplicationClass.getBaseUrl()
val refreshToken = context.getNewToken()
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}")
context.saveToken(it.accessToken, it.refreshToken)
}
}

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

private fun handleGetNewTokenFailure(
refreshTokenResponse: Response,
headerRequest: Request,
chain: Interceptor.Chain
): Response {
Timber.e("New Refresh Token Failure: ${refreshTokenResponse.code}")
context.saveToken(
accessToken = LoginStatus.EXPIRED.value,
refreshToken = LoginStatus.EXPIRED.value
)
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"
}

}

This file was deleted.

Loading
Loading