Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,7 @@ dependencies {
ksp(libs.hilt.compiler)
ksp(libs.hilt.manager)
}

tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
jvmTarget = "11"
}
Comment on lines +122 to +125
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 무슨 코드인가요..?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detekt 실행 시 빌드 실패가 발생해서 추가한 코드입니다!

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.konkuk.medicarecall.data.api.auth

import com.konkuk.medicarecall.data.dto.request.CertificationCodeRequestDto
import com.konkuk.medicarecall.data.dto.request.PhoneNumberConfirmRequestDto
import com.konkuk.medicarecall.data.dto.request.TokenRefreshRequestDto
import com.konkuk.medicarecall.data.dto.response.MemberTokenResponseDto
import com.konkuk.medicarecall.data.dto.response.VerificationResponseDto
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.Header
import retrofit2.http.POST

/** 인증과 관련된 API 모음 (토큰 갱신, 본인인증, 로그아웃) */

interface AuthService {
@POST("auth/refresh")
suspend fun refreshToken(@Body req: TokenRefreshRequestDto)
: Response<MemberTokenResponseDto>

@POST("verifications")
suspend fun requestCertificationCode(@Body req: CertificationCodeRequestDto)
: Response<Unit>

@POST("verifications/confirmation")
suspend fun confirmPhoneNumber(@Body req: PhoneNumberConfirmRequestDto)
: Response<VerificationResponseDto>

@POST("auth/logout")
suspend fun logout(
@Header("Authorization") authorization: String // "Bearer <refresh>"
): Response<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.request.ElderHealthRegisterRequestDto
import com.konkuk.medicarecall.data.dto.request.ElderRegisterRequestDto
Expand All @@ -19,4 +19,4 @@ interface ElderRegisterService {
@Path("elderId") elderId: Int,
@Body request: ElderHealthRegisterRequestDto
): Response<Unit>
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.request.ElderRegisterRequestDto
import com.konkuk.medicarecall.data.dto.response.CallTimeResponseDto
Expand Down Expand Up @@ -40,4 +40,4 @@ interface EldersInfoService {
suspend fun getCallTimes(
@Path("elderId") elderId: Int,
): Response<CallTimeResponseDto>
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.GlucoseResponseDto
import retrofit2.Response
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.HealthResponseDto
import retrofit2.http.GET
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.HomeResponseDto
import com.konkuk.medicarecall.data.dto.request.ImmediateCallRequestDto
import com.konkuk.medicarecall.data.dto.response.HomeResponseDto
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.MealResponseDto
import retrofit2.http.GET
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.MedicineResponseDto
import retrofit2.Response
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.MentalResponseDto
import retrofit2.http.GET
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.request.SetCallTimeRequestDto
import retrofit2.Response
Expand All @@ -12,4 +12,4 @@ interface SetCallService {
@Path("elderId") elderId: Int,
@Body body: SetCallTimeRequestDto
): Response<Unit>
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.SleepResponseDto
import retrofit2.http.GET
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.StatisticsResponseDto
import retrofit2.http.GET
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.elders

import com.konkuk.medicarecall.data.dto.response.EldersSubscriptionResponseDto
import retrofit2.Response
Expand All @@ -8,4 +8,4 @@ interface SubscribeService {
// elders 구독 정보 조회
@GET("elders/subscriptions")
suspend fun getElderSubscriptions(): Response<List<EldersSubscriptionResponseDto>>
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.member

import com.konkuk.medicarecall.data.dto.request.MemberRegisterRequestDto
import com.konkuk.medicarecall.data.dto.response.MemberTokenResponseDto
Expand All @@ -13,4 +13,4 @@ interface MemberRegisterService {
@Header("Authorization") header: String,
@Body request: MemberRegisterRequestDto
): Response<MemberTokenResponseDto>
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.member

import com.konkuk.medicarecall.data.dto.response.MyInfoResponseDto
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST

interface SettingService {
Expand All @@ -18,8 +17,4 @@ interface SettingService {
@Body userUpdateRequestDto: MyInfoResponseDto
): Response<MyInfoResponseDto> // 추후 수정 필요

@POST("auth/logout")
suspend fun logout(
@Header("Authorization") authorization: String // "Bearer <refresh>"
): Response<Unit>
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.notice

import com.konkuk.medicarecall.data.dto.response.NoticesResponseDto
import retrofit2.Response
Expand All @@ -8,4 +8,4 @@ interface NoticeService {
// 공지사항 조회
@GET("notices")
suspend fun getNotices(): Response<List<NoticesResponseDto>>
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.konkuk.medicarecall.data.api
package com.konkuk.medicarecall.data.api.payments

import com.konkuk.medicarecall.data.dto.request.ReservePayRequestDto
import com.konkuk.medicarecall.data.dto.response.ReservePayResponseDto
Expand All @@ -13,4 +13,4 @@ interface NaverPayService {
suspend fun postReservePay(
@Body request: ReservePayRequestDto
): Response<ReservePayResponseDto>
}
}
50 changes: 22 additions & 28 deletions app/src/main/java/com/konkuk/medicarecall/data/di/ApiModule.kt
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
package com.konkuk.medicarecall.data.di

import com.konkuk.medicarecall.data.api.ElderRegisterService
import com.konkuk.medicarecall.data.api.EldersInfoService
import com.konkuk.medicarecall.data.api.MemberRegisterService
import com.konkuk.medicarecall.data.api.NaverPayService
import com.konkuk.medicarecall.data.api.NoticeService
import com.konkuk.medicarecall.data.api.SetCallService
import com.konkuk.medicarecall.data.api.SettingService
import com.konkuk.medicarecall.data.api.SubscribeService
import com.konkuk.medicarecall.data.api.TokenRefreshService
import com.konkuk.medicarecall.data.api.VerificationService
import com.konkuk.medicarecall.data.api.HomeService
import com.konkuk.medicarecall.data.api.GlucoseService
import com.konkuk.medicarecall.data.api.MealService
import com.konkuk.medicarecall.data.api.MedicineService
import com.konkuk.medicarecall.data.api.SleepService
import com.konkuk.medicarecall.data.api.HealthService
import com.konkuk.medicarecall.data.api.MentalService
import com.konkuk.medicarecall.data.api.StatisticsService
import com.konkuk.medicarecall.data.api.elders.HomeService
import com.konkuk.medicarecall.data.api.auth.AuthService
import com.konkuk.medicarecall.data.api.elders.ElderRegisterService
import com.konkuk.medicarecall.data.api.elders.EldersInfoService
import com.konkuk.medicarecall.data.api.elders.GlucoseService
import com.konkuk.medicarecall.data.api.elders.HealthService
import com.konkuk.medicarecall.data.api.elders.MealService
import com.konkuk.medicarecall.data.api.elders.MedicineService
import com.konkuk.medicarecall.data.api.elders.MentalService
import com.konkuk.medicarecall.data.api.elders.SetCallService
import com.konkuk.medicarecall.data.api.elders.SleepService
import com.konkuk.medicarecall.data.api.elders.StatisticsService
import com.konkuk.medicarecall.data.api.elders.SubscribeService
import com.konkuk.medicarecall.data.api.member.MemberRegisterService
import com.konkuk.medicarecall.data.api.member.SettingService
import com.konkuk.medicarecall.data.api.notice.NoticeService
import com.konkuk.medicarecall.data.api.payments.NaverPayService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -31,16 +30,16 @@ object ApiModule {

@Provides
@Singleton
fun provideEldersInfoService(retrofit: Retrofit): EldersInfoService {
return retrofit.create(EldersInfoService::class.java)
}
fun provideAuthService(retrofit: Retrofit): AuthService =
retrofit.create(AuthService::class.java)

@Provides
@Singleton
fun provideVerificationService(retrofit: Retrofit): VerificationService {
return retrofit.create(VerificationService::class.java)
fun provideEldersInfoService(retrofit: Retrofit): EldersInfoService {
return retrofit.create(EldersInfoService::class.java)
}


@Provides
@Singleton
fun provideMemberRegisterService(retrofit: Retrofit): MemberRegisterService {
Expand Down Expand Up @@ -83,11 +82,6 @@ object ApiModule {
return retrofit.create(NaverPayService::class.java)
}

@Provides
@Singleton
fun provideTokenRefreshService(retrofit: Retrofit): TokenRefreshService {
return retrofit.create(TokenRefreshService::class.java)
}

@Provides
@Singleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.konkuk.medicarecall.data.di

import android.util.Log
import com.konkuk.medicarecall.BuildConfig
import com.konkuk.medicarecall.data.api.TokenRefreshService
import com.konkuk.medicarecall.data.api.auth.AuthService
import com.konkuk.medicarecall.data.network.AuthAuthenticator
import com.konkuk.medicarecall.data.network.AuthInterceptor
import com.konkuk.medicarecall.data.repository.DataStoreRepository
Expand Down Expand Up @@ -34,9 +34,9 @@ object NetworkModule {
@Singleton
fun provideAuthAuthenticator(
dataStoreRepository: DataStoreRepository,
tokenRefreshService: dagger.Lazy<TokenRefreshService>,
authService: dagger.Lazy<AuthService>
): AuthAuthenticator {
return AuthAuthenticator(dataStoreRepository, tokenRefreshService)
return AuthAuthenticator(dataStoreRepository, authService)
Comment on lines 35 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 코드에서 순환 의존성 때문에 Lazy 로 선언하신 것 같습니다.

  • AuthService → Retrofit → OkHttpClient → AuthAuthenticator → AuthService
    현재 위와 같이 순환 의존성이 있어서, 맨 뒤 AuthService 를 Lazy 로 선언해서 빌드 시에 순환 참조가 되지 않도록 하는 셈인데,

위와 같은 상황을 방지하게 위해 지연 생성을 하기 보단, tokenRepository를 사용해서 하면 좋을 것 같습니다!

현재 PR 에 대한 내용은 아니니 추후 참고용으로 달아놓을게요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피드백 감사합니다! 말씀 주신 부분 추후 리팩토링 시 참고하면 좋을 것 같아요

}

@Provides
Expand All @@ -52,11 +52,13 @@ object NetworkModule {
fun provideOkHttpClient(
authInterceptor: Interceptor,
loggingInterceptor: HttpLoggingInterceptor,
authAuthenticator: AuthAuthenticator
): OkHttpClient {
return OkHttpClient.Builder()
.readTimeout(20, TimeUnit.SECONDS)
.addInterceptor(authInterceptor)
.addInterceptor(loggingInterceptor)
.authenticator(authAuthenticator)
.build()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.konkuk.medicarecall.data.network

import android.util.Log
import com.konkuk.medicarecall.data.api.TokenRefreshService
import com.konkuk.medicarecall.data.api.auth.AuthService
import com.konkuk.medicarecall.data.dto.request.TokenRefreshRequestDto
import com.konkuk.medicarecall.data.repository.DataStoreRepository
import dagger.Lazy
import kotlinx.coroutines.runBlocking
import okhttp3.Authenticator
import okhttp3.Request
Expand All @@ -14,7 +13,7 @@ import javax.inject.Inject

class AuthAuthenticator @Inject constructor(
private val dataStoreRepository: DataStoreRepository,
private val tokenRefreshService: Lazy<TokenRefreshService> // 순환 참조 방지를 위해 Lazy 주입
private val authService: dagger.Lazy<AuthService> //순환 참조 방지
) : Authenticator {

override fun authenticate(route: Route?, response: Response): Request? {
Expand Down Expand Up @@ -46,7 +45,7 @@ class AuthAuthenticator @Inject constructor(

// 6. 토큰 갱신 API 호출 (runBlocking 사용)
val refreshResponse = runBlocking {
tokenRefreshService.get().refreshToken(TokenRefreshRequestDto(refreshToken))
authService.get().refreshToken(TokenRefreshRequestDto(refreshToken))
}
Comment on lines 47 to 49
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

리프레시 호출이 동일 OkHttp(인터셉터/Authentictor 포함)를 타는지 확인 필요

authService.get().refreshToken(...)가 현재 클라이언트의 AuthInterceptor/AuthAuthenticator를 그대로 타면, 401 시 재귀가 발생합니다. 리프레시 전용 Retrofit(인터셉터·Authenticator 미적용) 또는 인터셉터에서 리프레시 경로를 명시적으로 스킵하는지 확인 부탁드립니다. 필요 시 @Named 클라이언트 분리 권장.


🏁 Script executed:

#!/bin/bash
# AuthService 제공자/클라이언트 배선 확인
rg -nP --type=kt -C3 'provideAuthService|Retrofit\\s*\\.\\s*create\\(\\s*AuthService::class' app

# AuthInterceptor가 리프레시/인증 경로를 스킵하는지 확인
rg -nP --type=kt -C3 'class\\s+AuthInterceptor\\b|intercept\\(|encodedPath|auth/refresh|verification' app

# 별도 no-auth/refresh 클라이언트 존재 여부
rg -nP --type=kt -C2 '@Named\\(|@Qualifier|noAuth|unauth|refresh' app

Length of output: 218


스크립트 패턴의 괄호 이스케이프가 빠져 에러가 발생한 것 같습니다. 아래 수정된 스크립트를 실행해 리프레시 전용 클라이언트 분리 여부와 인터셉터/Authenticator 스킵 로직을 확인해 주세요.


🏁 Script executed:

#!/bin/bash
# AuthService 제공자/클라이언트 배선 확인
rg -nP --type=kt -C3 'provideAuthService' app
rg -nP --type=kt -C3 'Retrofit\s*\.create\(\s*AuthService::class\s*\)' app

# AuthInterceptor가 리프레시/인증 경로를 스킵하는지 확인
rg -nP --type=kt -C3 'class\s+AuthInterceptor' app
rg -nP --type=kt -C3 'fun\s+intercept' app
rg -nP --type=kt -C3 'encodedPath.*refresh' app

# 별도 no-auth/refresh 클라이언트 존재 여부
rg -nP --type=kt -C2 '@Named.*(noAuth|unauth|refresh)' app

Length of output: 161


ripgrep에서 --type=kt를 인식하지 못하는 것 같습니다. 글로브 필터로 .kt 파일을 지정해 다시 실행해 보세요.


🏁 Script executed:

#!/bin/bash
# AuthService 제공자/클라이언트 배선 확인
rg -g '*.kt' -n -C3 'provideAuthService' app
rg -g '*.kt' -n -C3 'Retrofit\s*\.create\(\s*AuthService::class\s*\)' app

# AuthInterceptor가 리프레시/인증 경로를 스킵하는지 확인
rg -g '*.kt' -n -C3 'class\s+AuthInterceptor\b' app
rg -g '*.kt' -n -C3 'fun\s+intercept\b' app
rg -g '*.kt' -n -C3 'encodedPath.*refresh' app

# 별도 no-auth/refresh 클라이언트 존재 여부
rg -g '*.kt' -n -C2 '@Named.*(noAuth|unauth|refresh)' app

Length of output: 2204


리프레시 전용 Retrofit 클라이언트 분리 필요
현재 authService.get().refreshToken(...)가 동일한 OkHttp 클라이언트(인터셉터/Authenticator 포함)를 사용해 호출되어 401 응답 시 무한 재귀 위험이 있습니다.
리프레시 전용 Retrofit 클라이언트를 @Named 또는 @Qualifier로 분리하거나, AuthInterceptor에서 refresh 경로를 명시적으로 스킵하도록 구현하세요.

🤖 Prompt for AI Agents
In app/src/main/java/com/konkuk/medicarecall/data/network/AuthAuthenticator.kt
around lines 47-49, the code calls authService.get().refreshToken(...) using the
same OkHttp client (with interceptors/Authenticator), which risks infinite
recursion on 401 during token refresh; create and inject a dedicated
Retrofit/OkHttp client for refresh calls (annotated with @Named or a custom
@Qualifier) that has no Authenticator or request interceptor that triggers token
refresh, or modify the interceptor to explicitly skip the refresh endpoint
(e.g., check request.url.path and return without adding auth/refresh logic);
update DI to provide both the regular authService and a refresh-only authService
and use the refresh-only instance inside runBlocking so refreshToken requests do
not pass through the Authenticator/interceptors.


return if (refreshResponse.isSuccessful && refreshResponse.body() != null) {
Expand Down Expand Up @@ -74,4 +73,4 @@ class AuthAuthenticator @Inject constructor(
}
}
}
}
}
Loading