Skip to content

Commit

Permalink
[MERGE] #96 -> develop
Browse files Browse the repository at this point in the history
[FEAT/#96] ํ† ํฐ ์žฌ๋ฐœ๊ธ‰ / ์„œ๋ฒ„ํ†ต์‹  ๊ตฌํ˜„
  • Loading branch information
leeeyubin authored Jul 17, 2024
2 parents 888b996 + 7d148ab commit 824946a
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 5 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ dependencies {
implementation(libs.retrofit2.kotlinx.serialization.converter)
implementation(libs.timber)
implementation(libs.ossLicense)
implementation(libs.process.phoenix)

debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
Expand Down
89 changes: 89 additions & 0 deletions app/src/main/java/com/terning/point/di/AuthInterceptor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.terning.point.di

import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
import com.jakewharton.processphoenix.ProcessPhoenix
import com.terning.core.extension.stringToast
import com.terning.data.local.TerningDataStore
import com.terning.domain.repository.TokenReissueRepository
import com.terning.feature.main.MainActivity
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import timber.log.Timber
import javax.inject.Inject

class AuthInterceptor @Inject constructor(
private val tokenReissueRepository: TokenReissueRepository,
private val terningDataStore: TerningDataStore,
@ApplicationContext private val context: Context
) : Interceptor {

override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()

Timber.d("GET ACCESS TOKEN : ${terningDataStore.accessToken}")

val authRequest = if (terningDataStore.accessToken.isNotBlank()) {
originalRequest.newBuilder().newAuthBuilder().build()
} else {
originalRequest
}

val response = chain.proceed(authRequest)

when (response.code) {
CODE_TOKEN_EXPIRED -> {
try {
runBlocking {
tokenReissueRepository.postReissueToken(
terningDataStore.refreshToken
)
}.onSuccess { data ->
terningDataStore.apply {
refreshToken = data.refreshToken
}

response.close()

val newRequest =
authRequest.newBuilder().removeHeader(AUTHORIZATION).newAuthBuilder()
.build()

return chain.proceed(newRequest)
}
} catch (t: Throwable) {
Timber.d(t.message)
}

terningDataStore.clearInfo()

Handler(Looper.getMainLooper()).post {
context.stringToast(TOKEN_EXPIRED_ERROR)
Handler(Looper.getMainLooper()).post {
ProcessPhoenix.triggerRebirth(
context,
Intent(context, MainActivity::class.java)
)
}
}
}
}
return response
}

private fun Request.Builder.newAuthBuilder() =
this.addHeader(AUTHORIZATION, "$BEARER ${terningDataStore.accessToken}")

companion object {
private const val CODE_TOKEN_EXPIRED = 401
private const val TOKEN_EXPIRED_ERROR = "ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜์—ˆ์–ด์š”\n๋‹ค์‹œ ๋กœ๊ทธ์ธ ํ•ด์ฃผ์„ธ์š”"
private const val BEARER = "Bearer"
private const val AUTHORIZATION = "Authorization"
}

}
6 changes: 6 additions & 0 deletions app/src/main/java/com/terning/point/di/DataSourceModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package com.terning.point.di

import com.terning.data.datasource.AuthDataSource
import com.terning.data.datasource.SearchDataSource
import com.terning.data.datasource.TokenReissueDataSource
import com.terning.data.datasourceimpl.AuthDataSourceImpl
import com.terning.data.datasourceimpl.SearchDataSourceImpl
import com.terning.data.datasourceimpl.TokenReissueDataSourceImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand All @@ -22,4 +24,8 @@ abstract class DataSourceModule {
@Singleton
abstract fun bindSearchViewsDataSource(searchViewsDataSourceImpl: SearchDataSourceImpl):
SearchDataSource

@Binds
@Singleton
abstract fun bindTokenReissueDataSource(tokenReissueDataSourceImpl: TokenReissueDataSourceImpl): TokenReissueDataSource
}
6 changes: 6 additions & 0 deletions app/src/main/java/com/terning/point/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package com.terning.point.di

import com.terning.data.repositoryimpl.AuthRepositoryImpl
import com.terning.data.repositoryimpl.SearchViewsRepositoryImpl
import com.terning.data.repositoryimpl.TokenReissueRepositoryImpl
import com.terning.data.repositoryimpl.TokenRepositoryImpl
import com.terning.domain.repository.AuthRepository
import com.terning.domain.repository.SearchRepository
import com.terning.domain.repository.TokenReissueRepository
import com.terning.domain.repository.TokenRepository
import dagger.Binds
import dagger.Module
Expand All @@ -27,4 +29,8 @@ abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindSearchViewsRepository(searchViewsRepositoryImpl: SearchViewsRepositoryImpl): SearchRepository

@Binds
@Singleton
abstract fun bindTokenReissueRepository(tokenReissueRepositoryImpl: TokenReissueRepositoryImpl): TokenReissueRepository
}
38 changes: 34 additions & 4 deletions app/src/main/java/com/terning/point/di/RetrofitModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.terning.core.extension.isJsonArray
import com.terning.core.extension.isJsonObject
import com.terning.point.BuildConfig.BASE_URL
import com.terning.point.di.qualifier.JWT
import com.terning.point.di.qualifier.REISSUE
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand Down Expand Up @@ -57,8 +58,25 @@ object RetrofitModule {

@Provides
@Singleton
fun provideOkHttpClient(
loggingInterceptor: Interceptor
@JWT
fun provideAuthInterceptor(authInterceptor: AuthInterceptor): Interceptor = authInterceptor

@Provides
@Singleton
@JWT
fun provideJWTOkHttpClient(
loggingInterceptor: Interceptor,
@JWT authInterceptor: Interceptor,
): OkHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(authInterceptor)
.build()

@Provides
@Singleton
@REISSUE
fun provideReissueOkHttpClient(
loggingInterceptor: Interceptor,
): OkHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
Expand All @@ -67,12 +85,24 @@ object RetrofitModule {
@Singleton
@JWT
fun provideJWTRetrofit(
client: OkHttpClient,
factory: Converter.Factory
@JWT client: OkHttpClient,
factory: Converter.Factory,
): Retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(factory)
.build()

@Provides
@Singleton
@REISSUE
fun provideReissueRetrofit(
@REISSUE client: OkHttpClient,
factory: Converter.Factory,
): Retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(factory)
.build()

}
7 changes: 7 additions & 0 deletions app/src/main/java/com/terning/point/di/ServiceModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.terning.point.di

import com.terning.data.service.AuthService
import com.terning.data.service.SearchService
import com.terning.data.service.TokenReissueService
import com.terning.point.di.qualifier.JWT
import com.terning.point.di.qualifier.REISSUE
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -23,4 +25,9 @@ object ServiceModule {
@Singleton
fun provideSearchService(@JWT retrofit: Retrofit): SearchService =
retrofit.create(SearchService::class.java)

@Provides
@Singleton
fun provideTokenReissueService(@REISSUE retrofit: Retrofit): TokenReissueService =
retrofit.create(TokenReissueService::class.java)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ import javax.inject.Qualifier

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class JWT
annotation class JWT

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class REISSUE
4 changes: 4 additions & 0 deletions core/src/main/java/com/terning/core/extension/ContextExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ fun Context.toast(@StringRes message: Int) {
Toast.makeText(this, getString(message), Toast.LENGTH_SHORT).show()
}

fun Context.stringToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

fun Context.longToast(@StringRes message: Int) {
Toast.makeText(this, getString(message), Toast.LENGTH_SHORT).show()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.terning.data.datasource

import com.terning.data.dto.BaseResponse
import com.terning.data.dto.response.TokenReissueResponseDto
import com.terning.domain.entity.response.TokenReissueResponseModel

interface TokenReissueDataSource {
suspend fun postReissueToken(
authorization: String,
): BaseResponse<TokenReissueResponseDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.terning.data.datasourceimpl

import com.terning.data.datasource.TokenReissueDataSource
import com.terning.data.dto.BaseResponse
import com.terning.data.dto.response.TokenReissueResponseDto
import com.terning.data.service.TokenReissueService
import javax.inject.Inject

class TokenReissueDataSourceImpl @Inject constructor(
private val tokenReissueService: TokenReissueService
) : TokenReissueDataSource {
override suspend fun postReissueToken(
authorization: String
): BaseResponse<TokenReissueResponseDto> =
tokenReissueService.postReissueToken(authorization)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.terning.data.dto.response

import com.terning.domain.entity.response.TokenReissueResponseModel
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class TokenReissueResponseDto(
@SerialName("refreshToken")
val refreshToken: String
) {
fun toTokenReissueResponseModel() = TokenReissueResponseModel(refreshToken = refreshToken)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.terning.data.repositoryimpl

import com.terning.data.datasource.TokenReissueDataSource
import com.terning.domain.entity.response.TokenReissueResponseModel
import com.terning.domain.repository.TokenReissueRepository
import javax.inject.Inject

class TokenReissueRepositoryImpl @Inject constructor(
private val tokenReissueDataSource: TokenReissueDataSource
) : TokenReissueRepository {
override suspend fun postReissueToken(
authorization: String
): Result<TokenReissueResponseModel> =
runCatching {
tokenReissueDataSource.postReissueToken(
authorization = authorization
).result.toTokenReissueResponseModel()
}
}
13 changes: 13 additions & 0 deletions data/src/main/java/com/terning/data/service/TokenReissueService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.terning.data.service

import com.terning.data.dto.BaseResponse
import com.terning.data.dto.response.TokenReissueResponseDto
import retrofit2.http.Header
import retrofit2.http.POST

interface TokenReissueService {
@POST("/api/v1/auth/token-reissue")
suspend fun postReissueToken(
@Header("Authorization") authorization: String,
): BaseResponse<TokenReissueResponseDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.terning.domain.entity.response

data class TokenReissueResponseModel (
val refreshToken : String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.terning.domain.repository

import com.terning.domain.entity.response.TokenReissueResponseModel

interface TokenReissueRepository {
suspend fun postReissueToken(
authorization: String,
): Result<TokenReissueResponseModel>
}
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ lifecycleRuntimeComposeAndroid = "2.8.2"
## Kakao
kakaoVersion = "2.20.1"

## ProcessPhoenix
processPhoenix = "2.0.0"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidxAppCompat" }
Expand Down Expand Up @@ -159,6 +162,8 @@ lottie = {group = "com.airbnb.android", name = "lottie", version.ref = "lottieVe

kakao-user = {group = "com.kakao.sdk", name = "v2-user", version.ref = "kakaoVersion"}

process-phoenix = {group = "com.jakewharton", name = "process-phoenix", version.ref = "processPhoenix"}

[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
Expand Down

0 comments on commit 824946a

Please sign in to comment.