[Feature/#179] authenticator 구현#180
Conversation
## Walkthrough
기존의 토큰 만료 및 갱신 처리가 TokenInterceptor에서 TokenAuthenticator 클래스로 이전되었습니다. TokenAuthenticator는 OkHttp Authenticator 인터페이스를 구현하여 401 응답 시 토큰을 갱신하고, 성공 시 재요청, 실패 시 토큰 삭제 및 앱 재시작을 처리합니다. 관련 의존성 및 모듈 설정도 이에 맞게 변경되었습니다.
## Changes
| 파일(들) | 변경 요약 |
|---|---|
| core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultAuthRepository.kt<br>core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultCommunityRepository.kt<br>core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultFeedImageRepository.kt<br>core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultProfileRepository.kt | `runHandledCatching` import 경로를 `com.teamwable.network.util`로 변경 |
| core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt | TokenAuthenticator 클래스 신규 추가 (OkHttp Authenticator 구현, 토큰 갱신/재요청/실패 처리) |
| core/network/src/main/java/com/teamwable/network/TokenInterceptor.kt | 토큰 만료/갱신/재시도 로직 삭제, 단순 Authorization 헤더 추가만 수행하도록 단순화 |
| core/network/src/main/java/com/teamwable/network/di/NetworkModule.kt | OkHttpClient에 TokenAuthenticator 추가, @AccessToken 어노테이션 제거 및 관련 시그니처 수정 |
| core/network/src/main/java/com/teamwable/network/di/Qualifier.kt | AccessToken Qualifier 어노테이션 삭제 |
| core/network/src/main/java/com/teamwable/network/util/runSuspendCatching.kt | 패키지명을 `com.teamwable.network.util`로 변경, 불필요 import 제거 |
| core/common/src/main/java/com/teamwable/common/restarter/AppReStarter.kt<br>core/common/src/main/java/com/teamwable/common/restarter/AppReStarterModule.kt<br>core/common/src/main/java/com/teamwable/common/restarter/DefaultAppReStarter.kt | 앱 재시작 및 토스트 표시를 위한 AppReStarter 인터페이스 및 구현체, 모듈 추가 |
| feature/profile/src/main/java/com/teamwable/profile/hamburger/ProfileDeleteConfirmFragment.kt<br>feature/profile/src/main/java/com/teamwable/profile/hamburger/ProfileHamburgerBottomSheet.kt | 앱 재시작 로직을 Intent 직접 호출에서 AppReStarter 주입 및 호출로 변경 |
## Sequence Diagram(s)
```mermaid
sequenceDiagram
participant App
participant OkHttpClient
participant TokenInterceptor
participant TokenAuthenticator
participant AuthService
participant DataStore
App->>OkHttpClient: API 요청
OkHttpClient->>TokenInterceptor: 요청 인터셉트
TokenInterceptor->>DataStore: AccessToken 조회
TokenInterceptor->>OkHttpClient: Authorization 헤더 추가 후 요청 진행
OkHttpClient->>서버: API 요청
서버-->>OkHttpClient: 401 Unauthorized 응답
OkHttpClient->>TokenAuthenticator: authenticate 호출
TokenAuthenticator->>DataStore: RefreshToken 조회
TokenAuthenticator->>AuthService: 토큰 갱신 시도
alt 토큰 갱신 성공
AuthService-->>TokenAuthenticator: 새로운 토큰 반환
TokenAuthenticator->>DataStore: 토큰 저장
TokenAuthenticator->>OkHttpClient: 새로운 토큰으로 재요청 반환
else 토큰 갱신 실패
TokenAuthenticator->>DataStore: 토큰 삭제
TokenAuthenticator->>App: Toast 표시 및 앱 재시작
TokenAuthenticator->>OkHttpClient: null 반환 (요청 실패)
endAssessment against linked issues
Poem
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultProfileRepository.kt (1)
27-44: 에러 핸들링 패턴의 일관성을 개선하는 것을 고려해보세요.일부 메서드는
runHandledCatching을 사용하고 있지만, 다른 메서드들은runCatching과 수동 에러 핸들링을 사용하고 있습니다. 학습된 내용에 따르면 WABLE 프로젝트에서는 Repository 레이어에서runHandledCatching을 사용하여 중앙집중식 에러 핸들링을 권장합니다.모든 메서드에서 일관되게
runHandledCatching을 사용하는 것을 고려해보세요:- override suspend fun getProfileInfo(userId: Long): Result<Profile> = runCatching { - apiService.getProfileInfo(userId).data.toProfile() - }.onFailure { - return it.handleThrowable() - } + override suspend fun getProfileInfo(userId: Long): Result<Profile> = runHandledCatching { + apiService.getProfileInfo(userId).data.toProfile() + }core/network/src/main/java/com/teamwable/network/TokenInterceptor.kt (1)
14-21: Interceptor에서runBlocking사용 시 성능 영향모든 요청마다
runBlocking으로 토큰을 가져오는 것은 성능에 영향을 줄 수 있습니다. 토큰 캐싱을 고려해보세요.다음과 같은 개선을 제안합니다:
class TokenInterceptor @Inject constructor( private val dataStore: WablePreferencesDataSource, ) : Interceptor { + private var cachedToken: String? = null + override fun intercept(chain: Interceptor.Chain): Response { - val accessToken = runBlocking { dataStore.accessToken.first() } + val accessToken = cachedToken ?: runBlocking { + dataStore.accessToken.first().also { cachedToken = it } + } val authRequest: Request = chain.request().newBuilder() .addHeader("Authorization", accessToken) .build() return chain.proceed(authRequest) } + + // TokenAuthenticator에서 토큰 갱신 시 캐시 무효화 필요 + fun invalidateCache() { + cachedToken = null + } }또는 토큰을 Flow로 관찰하여 변경 시에만 업데이트하는 방식도 고려해볼 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultAuthRepository.kt(1 hunks)core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultCommunityRepository.kt(1 hunks)core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultFeedImageRepository.kt(1 hunks)core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultProfileRepository.kt(1 hunks)core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt(1 hunks)core/network/src/main/java/com/teamwable/network/TokenInterceptor.kt(1 hunks)core/network/src/main/java/com/teamwable/network/di/NetworkModule.kt(2 hunks)core/network/src/main/java/com/teamwable/network/di/Qualifier.kt(0 hunks)core/network/src/main/java/com/teamwable/network/util/runSuspendCatching.kt(1 hunks)
💤 Files with no reviewable changes (1)
- core/network/src/main/java/com/teamwable/network/di/Qualifier.kt
🧰 Additional context used
🧠 Learnings (4)
core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultProfileRepository.kt (1)
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#168
File: core/data/src/main/java/com/teamwable/data/gallery/GallerySaver.kt:22-34
Timestamp: 2025-06-08T14:50:22.089Z
Learning: WABLE Android 프로젝트에서는 에러 핸들링을 Repository 레이어에서 `runHandledCatching`을 사용하여 중앙집중식으로 처리합니다. 따라서 하위 레이어의 유틸리티 클래스(예: GallerySaver)에서는 별도의 try-catch 블록을 추가할 필요가 없습니다.
core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultAuthRepository.kt (1)
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#168
File: core/data/src/main/java/com/teamwable/data/gallery/GallerySaver.kt:22-34
Timestamp: 2025-06-08T14:50:22.089Z
Learning: WABLE Android 프로젝트에서는 에러 핸들링을 Repository 레이어에서 `runHandledCatching`을 사용하여 중앙집중식으로 처리합니다. 따라서 하위 레이어의 유틸리티 클래스(예: GallerySaver)에서는 별도의 try-catch 블록을 추가할 필요가 없습니다.
core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultFeedImageRepository.kt (1)
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#168
File: core/data/src/main/java/com/teamwable/data/gallery/GallerySaver.kt:22-34
Timestamp: 2025-06-08T14:50:22.089Z
Learning: WABLE Android 프로젝트에서는 에러 핸들링을 Repository 레이어에서 `runHandledCatching`을 사용하여 중앙집중식으로 처리합니다. 따라서 하위 레이어의 유틸리티 클래스(예: GallerySaver)에서는 별도의 try-catch 블록을 추가할 필요가 없습니다.
core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultCommunityRepository.kt (1)
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#168
File: core/data/src/main/java/com/teamwable/data/gallery/GallerySaver.kt:22-34
Timestamp: 2025-06-08T14:50:22.089Z
Learning: WABLE Android 프로젝트에서는 에러 핸들링을 Repository 레이어에서 `runHandledCatching`을 사용하여 중앙집중식으로 처리합니다. 따라서 하위 레이어의 유틸리티 클래스(예: GallerySaver)에서는 별도의 try-catch 블록을 추가할 필요가 없습니다.
🧬 Code Graph Analysis (1)
core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt (1)
core/network/src/main/java/com/teamwable/network/util/runSuspendCatching.kt (1)
runSuspendCatching(6-16)
🔇 Additional comments (6)
core/network/src/main/java/com/teamwable/network/util/runSuspendCatching.kt (1)
1-1: 패키지 이동이 적절하게 수행되었습니다.네트워크 관련 유틸리티를
network.util패키지로 이동시킨 것은 모듈 구조를 개선하고 관련 기능을 한 곳에 집중시키는 좋은 접근입니다.core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultProfileRepository.kt (1)
16-16: import 문 업데이트가 올바르게 수행되었습니다.유틸리티 함수가
network.util패키지로 이동한 것에 맞춰 import 문이 적절히 업데이트되었습니다.core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultFeedImageRepository.kt (1)
7-7: import 문 업데이트가 올바르게 수행되었습니다.유틸리티 함수가
network.util패키지로 이동한 것에 맞춰 import 문이 적절히 업데이트되었습니다.core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultAuthRepository.kt (1)
8-8: import 문 업데이트가 올바르게 수행되었습니다.유틸리티 함수가
network.util패키지로 이동한 것에 맞춰 import 문이 적절히 업데이트되었습니다.core/data/src/main/java/com/teamwable/data/repositoryimpl/DefaultCommunityRepository.kt (1)
8-8: import 문 업데이트가 올바르게 수행되었습니다.유틸리티 함수가
network.util패키지로 이동한 것에 맞춰 import 문이 적절히 업데이트되었습니다. Flow 기반 메서드와 suspend 함수에서 각각 적절한 에러 핸들링 패턴을 사용하고 있습니다.core/network/src/main/java/com/teamwable/network/di/NetworkModule.kt (1)
38-48: 인증 처리 구조가 적절하게 분리되었습니다.TokenInterceptor와 TokenAuthenticator의 역할을 명확하게 분리한 것이 좋습니다. OkHttp의 권장 패턴을 잘 따르고 있습니다.
| private fun restartApp() { | ||
| val restartIntent = context.packageManager | ||
| .getLaunchIntentForPackage(context.packageName) | ||
| ?.component | ||
| ?.let(Intent::makeRestartActivityTask) | ||
|
|
||
| context.startActivity(restartIntent) | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
앱 재시작 로직 검증 필요
makeRestartActivityTask를 사용한 앱 재시작 로직이 모든 상황에서 올바르게 동작하는지 확인이 필요합니다.
다음 사항들을 확인해주세요:
- 백그라운드에서 실행될 때의 동작
- 다양한 Android 버전에서의 호환성
- 멀티 태스크 환경에서의 동작
🏁 Script executed:
#!/bin/bash
# Description: 앱 재시작 관련 코드 패턴 확인
# makeRestartActivityTask 사용 사례 검색
rg -A 5 "makeRestartActivityTask" --type kotlin
# Intent.FLAG_ACTIVITY_NEW_TASK 사용 확인
rg -A 5 "FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TASK" --type kotlinLength of output: 4071
앱 재시작 로직 검증 결과 및 개선 제안
- Intent.makeRestartActivityTask는 내부적으로 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK를 설정하므로 별도 플래그 추가는 불필요합니다.
- TokenAuthenticator.kt 외에도 ProfileHamburgerBottomSheet.kt, ProfileDeleteConfirmFragment.kt 에서 동일 패턴으로 구현되어 있습니다.
- 다만,
getLaunchIntentForPackage()가null을 반환할 경우startActivity(null)로 인해 예외가 발생할 수 있으므로, 호출 전/후에 반드시 null 체크 및 적절한 예외 처리(로그 출력 등)를 추가해주세요.
예시 수정안:
- val restartIntent = context.packageManager
- .getLaunchIntentForPackage(context.packageName)
- ?.component
- ?.let(Intent::makeRestartActivityTask)
- context.startActivity(restartIntent)
+ val restartIntent = context.packageManager
+ .getLaunchIntentForPackage(context.packageName)
+ ?.component
+ ?.let(Intent::makeRestartActivityTask)
+ restartIntent?.let {
+ context.startActivity(it)
+ } ?: run {
+ Timber.e("앱 재시작용 인텐트를 생성하지 못했습니다.")
+ }🤖 Prompt for AI Agents
In core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt around
lines 77 to 84, the restartApp function calls startActivity with a potentially
null intent from getLaunchIntentForPackage, which can cause an exception. To fix
this, add a null check after obtaining the restartIntent and before calling
startActivity; if restartIntent is null, log an appropriate error or handle the
case gracefully without calling startActivity with null.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (3)
core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt (3)
61-64: 네트워크 레이어에서 UI 작업 수행 문제네트워크 레이어에서 Toast 표시와 앱 재시작을 직접 처리하는 것은 관심사 분리 원칙에 위배됩니다.
이전 리뷰에서 제안한 대로 인증 실패 이벤트를 발행하는 콜백 메커니즘이나 이벤트 버스를 도입하여 UI 관련 로직을 프레젠테이션 레이어로 분리하는 것을 고려해보세요.
49-50: 토큰 저장 작업의 순서 보장 필요
updateAccessToken과updateRefreshToken호출이 순차적으로 완료되도록 보장해야 합니다.다음과 같이 수정하세요:
}.onSuccess { val newAccess = "Bearer ${it.data.accessToken}" - dataStore.updateAccessToken(newAccess) - dataStore.updateRefreshToken(it.data.refreshToken) + dataStore.updateAccessToken(newAccess) + dataStore.updateRefreshToken(it.data.refreshToken) return newAccess }.onFailure {두 작업이 모두 완료되기를 기다려야 합니다.
54-54: 데이터 클리어 작업 완료 보장 필요앱 재시작 전에
dataStore.clear()작업이 완료되도록 보장해야 합니다.다음과 같이 수정하세요:
}.onFailure { Timber.e(it) - dataStore.clear() + runBlocking { dataStore.clear() } notifyReLoginRequired() }
🧹 Nitpick comments (1)
core/common/src/main/java/com/teamwable/common/restarter/DefaultAppReStarter.kt (1)
16-16: 코루틴 스코프 관리 개선 고려현재
CoroutineScope(Dispatchers.Main)을 직접 생성하고 있습니다. 애플리케이션 생명주기와 연결된 스코프 사용을 고려해보세요.다음과 같은 대안을 고려할 수 있습니다:
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)또는 ApplicationScope 주입을 고려해보세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
core/common/src/main/java/com/teamwable/common/restarter/AppReStarter.kt(1 hunks)core/common/src/main/java/com/teamwable/common/restarter/AppReStarterModule.kt(1 hunks)core/common/src/main/java/com/teamwable/common/restarter/DefaultAppReStarter.kt(1 hunks)core/network/build.gradle.kts(1 hunks)core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt(1 hunks)feature/profile/src/main/java/com/teamwable/profile/hamburger/ProfileDeleteConfirmFragment.kt(4 hunks)feature/profile/src/main/java/com/teamwable/profile/hamburger/ProfileHamburgerBottomSheet.kt(3 hunks)
✅ Files skipped from review due to trivial changes (2)
- core/network/build.gradle.kts
- core/common/src/main/java/com/teamwable/common/restarter/AppReStarter.kt
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:32-42
Timestamp: 2025-07-17T15:00:12.687Z
Learning: OkHttp Authenticator에서 runBlocking 사용 시 메인 스레드 블로킹은 문제가 되지 않지만, 같은 OkHttp 인스턴스로 토큰 갱신 요청을 보내면 스레드 풀 고갈로 인한 데드락이 발생할 수 있다.
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:32-42
Timestamp: 2025-07-17T15:00:12.687Z
Learning: OkHttp의 Authenticator는 워커 스레드에서 실행되므로 runBlocking을 사용해도 메인 스레드를 블로킹하지 않는다.
core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt (2)
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:32-42
Timestamp: 2025-07-17T15:00:12.687Z
Learning: OkHttp Authenticator에서 runBlocking 사용 시 메인 스레드 블로킹은 문제가 되지 않지만, 같은 OkHttp 인스턴스로 토큰 갱신 요청을 보내면 스레드 풀 고갈로 인한 데드락이 발생할 수 있다.
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:32-42
Timestamp: 2025-07-17T15:00:12.687Z
Learning: OkHttp의 Authenticator는 워커 스레드에서 실행되므로 runBlocking을 사용해도 메인 스레드를 블로킹하지 않는다.
🧬 Code Graph Analysis (1)
core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt (1)
core/network/src/main/java/com/teamwable/network/util/runSuspendCatching.kt (1)
runSuspendCatching(6-16)
🔇 Additional comments (7)
feature/profile/src/main/java/com/teamwable/profile/hamburger/ProfileDeleteConfirmFragment.kt (1)
7-7: 의존성 주입을 통한 앱 재시작 로직 중앙화
AppReStarter인터페이스를 통해 앱 재시작 로직을 중앙화한 것은 좋은 개선입니다. 직접적인Intent사용을 제거하고 의존성 주입을 통해 관심사 분리를 잘 구현했습니다.Also applies to: 26-26, 35-36, 69-69
core/common/src/main/java/com/teamwable/common/restarter/AppReStarterModule.kt (1)
9-17: 표준적인 Dagger Hilt 모듈 구현
AppReStarter인터페이스의 싱글톤 바인딩이 적절하게 구현되었습니다. 애플리케이션 전체에서 사용되는 앱 재시작 기능에 대해 싱글톤 스코프가 적합합니다.feature/profile/src/main/java/com/teamwable/profile/hamburger/ProfileHamburgerBottomSheet.kt (1)
5-5: 일관된 앱 재시작 로직 적용
ProfileDeleteConfirmFragment와 동일한 패턴으로AppReStarter를 사용하여 앱 재시작 로직을 중앙화했습니다. 코드베이스 전반에 걸쳐 일관된 접근 방식이 적용되었습니다.Also applies to: 17-17, 23-24, 75-75
core/common/src/main/java/com/teamwable/common/restarter/DefaultAppReStarter.kt (1)
29-35: 토스트 관리 로직 적절히 구현됨기존 토스트를 취소하고 새 토스트를 표시하는 로직이 잘 구현되어 있습니다. 메모리 누수를 방지하고 사용자 경험을 향상시킵니다.
core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt (3)
25-38: 무한 재시도 방지 로직 적절히 구현됨401 응답과 이미 재시도된 요청을 확인하는 로직이 잘 구현되어 있습니다.
Authorization-Retry헤더를 사용한 재시도 방지 메커니즘이 적절합니다.
40-59: 토큰 갱신 로직의 동시성 처리 적절함
Mutex를 사용하여 동시 토큰 갱신 요청을 적절히 처리하고 있습니다. 하나의 갱신 작업만 실행되도록 보장하는 것이 좋습니다.
30-37: 별도 OkHttpClient 사용으로 데드락 위험 없음
AuthService는@WithoutTokenInterceptor가 붙은 별도의 Retrofit/OkHttpClient 인스턴스를 사용해 토큰 재발급 요청을 수행합니다. 따라서TokenAuthenticator의runBlocking블록이 같은 OkHttp 클라이언트를 재귀 호출하지 않으므로 스레드 풀 고갈에 따른 데드락은 발생하지 않습니다.
| override fun restartApp() { | ||
| scope.launch { | ||
| val restartIntent = context.packageManager | ||
| .getLaunchIntentForPackage(context.packageName) | ||
| ?.component | ||
| ?.let(Intent::makeRestartActivityTask) | ||
|
|
||
| context.startActivity(restartIntent) | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
앱 재시작 시 null 안전성 개선 필요
getLaunchIntentForPackage()가 null을 반환할 경우 startActivity(null)로 인한 예외가 발생할 수 있습니다.
다음과 같이 null 체크를 추가하세요:
override fun restartApp() {
scope.launch {
val restartIntent = context.packageManager
.getLaunchIntentForPackage(context.packageName)
?.component
?.let(Intent::makeRestartActivityTask)
-
- context.startActivity(restartIntent)
+
+ restartIntent?.let {
+ context.startActivity(it)
+ } ?: run {
+ // 로그 출력 또는 다른 처리
+ }
}
}🤖 Prompt for AI Agents
In
core/common/src/main/java/com/teamwable/common/restarter/DefaultAppReStarter.kt
around lines 18 to 27, the restartApp method calls startActivity with a
potentially null intent if getLaunchIntentForPackage returns null, which can
cause an exception. To fix this, add a null check before calling startActivity
to ensure the intent is not null, and only call startActivity if the intent is
valid.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
core/network/src/main/java/com/teamwable/network/di/NetworkModule.kt(2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:0-0
Timestamp: 2025-07-17T16:55:14.963Z
Learning: WABLE-ANDROID 프로젝트에서 AppReStarter 인터페이스 패턴을 사용하여 네트워크 레이어에서 UI 작업(토스트, 앱 재시작)을 분리한다. TokenAuthenticator에서 인증 실패 시 AppReStarter를 통해 UI 작업을 위임한다.
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:32-42
Timestamp: 2025-07-17T15:00:12.687Z
Learning: OkHttp Authenticator에서 runBlocking 사용 시 메인 스레드 블로킹은 문제가 되지 않지만, 같은 OkHttp 인스턴스로 토큰 갱신 요청을 보내면 스레드 풀 고갈로 인한 데드락이 발생할 수 있다.
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:32-42
Timestamp: 2025-07-17T15:00:12.687Z
Learning: OkHttp의 Authenticator는 워커 스레드에서 실행되므로 runBlocking을 사용해도 메인 스레드를 블로킹하지 않는다.
core/network/src/main/java/com/teamwable/network/di/NetworkModule.kt (3)
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:0-0
Timestamp: 2025-07-17T16:55:14.963Z
Learning: WABLE-ANDROID 프로젝트에서 AppReStarter 인터페이스 패턴을 사용하여 네트워크 레이어에서 UI 작업(토스트, 앱 재시작)을 분리한다. TokenAuthenticator에서 인증 실패 시 AppReStarter를 통해 UI 작업을 위임한다.
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:32-42
Timestamp: 2025-07-17T15:00:12.687Z
Learning: OkHttp의 Authenticator는 워커 스레드에서 실행되므로 runBlocking을 사용해도 메인 스레드를 블로킹하지 않는다.
Learnt from: chanubc
PR: Team-Wable/WABLE-ANDROID#180
File: core/network/src/main/java/com/teamwable/network/TokenAuthenticator.kt:32-42
Timestamp: 2025-07-17T15:00:12.687Z
Learning: OkHttp Authenticator에서 runBlocking 사용 시 메인 스레드 블로킹은 문제가 되지 않지만, 같은 OkHttp 인스턴스로 토큰 갱신 요청을 보내면 스레드 풀 고갈로 인한 데드락이 발생할 수 있다.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: PR Checker
🔇 Additional comments (4)
core/network/src/main/java/com/teamwable/network/di/NetworkModule.kt (4)
5-5: 새로운 TokenAuthenticator 도입을 확인했습니다.TokenAuthenticator 클래스가 추가되어 인증 처리 로직이 분리되었습니다. 이는 관심사 분리 원칙에 따른 좋은 아키텍처 개선입니다.
38-38: TokenInterceptor 의존성 단순화가 적절합니다.
@AccessToken어노테이션이 제거되고 구체적인TokenInterceptor타입으로 변경되었습니다. 이는 의존성 주입을 단순화하고 코드의 가독성을 향상시킵니다.
40-40: TokenAuthenticator 의존성 추가가 올바릅니다.새로운
TokenAuthenticator파라미터가 추가되어 401 응답 처리를 위한 인증자가 주입됩니다. 이전 학습 내용에 따르면 이 클래스는 AppReStarter 인터페이스를 통해 UI 작업을 적절히 분리하고 있습니다.
47-47: OkHttpClient에 authenticator 설정이 적절합니다.
.authenticator(tokenAuthenticator)가 추가되어 401 Unauthorized 응답 시 자동으로 토큰 갱신을 처리할 수 있습니다. 이전 학습 내용에 따르면 TokenAuthenticator는 워커 스레드에서 실행되므로 성능상 문제가 없습니다.
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai Changes, Sequence diagaram등에서 코드블록이 제대로 랜더링 되지가 않아 |
|
Tip For best results, initiate chat on the files or code changes. @chanubc 죄송합니다! 제가 생성한 마크다운에서 코드블록이 제대로 렌더링되지 않았네요. 문제가 된 부분들을 올바른 형식으로 다시 제공해드리겠습니다: Changes
Sequence DiagramsequenceDiagram
participant App
participant OkHttpClient
participant TokenInterceptor
participant TokenAuthenticator
participant AuthService
participant DataStore
App->>OkHttpClient: API 요청
OkHttpClient->>TokenInterceptor: 요청 인터셉트
TokenInterceptor->>DataStore: AccessToken 조회
TokenInterceptor->>OkHttpClient: Authorization 헤더 추가 후 요청 진행
OkHttpClient->>서버: API 요청
서버-->>OkHttpClient: 401 Unauthorized 응답
OkHttpClient->>TokenAuthenticator: authenticate 호출
TokenAuthenticator->>DataStore: RefreshToken 조회
TokenAuthenticator->>AuthService: 토큰 갱신 시도
alt 토큰 갱신 성공
AuthService-->>TokenAuthenticator: 새로운 토큰 반환
TokenAuthenticator->>DataStore: 토큰 저장
TokenAuthenticator->>OkHttpClient: 새로운 토큰으로 재요청 반환
else 토큰 갱신 실패
TokenAuthenticator->>DataStore: 토큰 삭제
TokenAuthenticator->>App: Toast 표시 및 앱 재시작
TokenAuthenticator->>OkHttpClient: null 반환 (요청 실패)
end
이제 제대로 렌더링될 것입니다! 향후 마크다운 형식에 더 주의를 기울이겠습니다. 🧠 Learnings used |
| private val mutex = Mutex() | ||
|
|
||
| override fun authenticate(route: Route?, response: Response): Request? { | ||
| if (response.code != 401) return null |
There was a problem hiding this comment.
토큰 만료만 401로 오나요?! 따로 토큰 만료인지 확인하는 분기가 없어도 되는지 궁금합니다!
| } | ||
|
|
||
| private suspend fun refreshToken(): String? { | ||
| return mutex.withLock { |
|
token만료 테스트 해보시고 알려주시와요~! |
|
@sohyun127 |
✅ 𝗖𝗵𝗲𝗰𝗸-𝗟𝗶𝘀𝘁
📌 𝗜𝘀𝘀𝘂𝗲𝘀
📎𝗪𝗼𝗿𝗸 𝗗𝗲𝘀𝗰𝗿𝗶𝗽𝘁𝗶𝗼𝗻
📷 𝗦𝗰𝗿𝗲𝗲𝗻𝘀𝗵𝗼𝘁
💬 𝗧𝗼 𝗥𝗲𝘃𝗶𝗲𝘄𝗲𝗿𝘀
아직 access token만료 테스트는 못해봐서 해보고 말씀드릴게요!
token 값 다른 것 넣는거 말고 테스트 하는법 어떤거 있었죠?
Summary by CodeRabbit
신규 기능
리팩터링
기타