Skip to content

Commit

Permalink
Merge pull request #71 from team-JMT/feat/auto_login
Browse files Browse the repository at this point in the history
자동 로그인 기능 구현
  • Loading branch information
soopeach authored Sep 10, 2023
2 parents bad6aff + 75ac888 commit 9c12143
Show file tree
Hide file tree
Showing 18 changed files with 194 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.gdsc.data.datasource

import org.gdsc.data.model.Response
import org.gdsc.domain.model.response.TokenResponse

interface TokenDataSource {

suspend fun postRefreshToken(refreshToken: String): Response<TokenResponse>
}
15 changes: 15 additions & 0 deletions data/src/main/java/org/gdsc/data/datasource/TokenDataSourceImpl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.gdsc.data.datasource

import org.gdsc.data.model.Response
import org.gdsc.data.network.TokenAPI
import org.gdsc.domain.model.request.RefreshTokenRequest
import org.gdsc.domain.model.response.TokenResponse
import javax.inject.Inject

class TokenDataSourceImpl @Inject constructor(
private val tokenAPI: TokenAPI
): TokenDataSource {
override suspend fun postRefreshToken(refreshToken: String): Response<TokenResponse> {
return tokenAPI.refreshToken(RefreshTokenRequest(refreshToken))
}
}
7 changes: 7 additions & 0 deletions data/src/main/java/org/gdsc/data/di/ApiModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.gdsc.data.network.LoginAPI
import org.gdsc.data.network.RestaurantAPI
import org.gdsc.data.network.TokenAPI
import org.gdsc.data.network.UserAPI
import retrofit2.Retrofit
import javax.inject.Singleton
Expand All @@ -32,4 +33,10 @@ class ApiModule {
return retrofit.create(UserAPI::class.java)
}

@Provides
@Singleton
fun provideTokenApi(@AuthClient retrofit: Retrofit): TokenAPI {
return retrofit.create(TokenAPI::class.java)
}

}
7 changes: 4 additions & 3 deletions data/src/main/java/org/gdsc/data/di/NetworkModule.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.gdsc.data.di

import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.gdsc.data.network.AuthInterceptor
import org.gdsc.domain.repository.TokenManager
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton
Expand All @@ -33,15 +34,15 @@ class NetworkModule {
@AuthClient
@Provides
@Singleton
fun provideAuthorizedApiClient(tokenManager: TokenManager): Retrofit {
fun provideAuthorizedApiClient(@ApplicationContext context: Context): Retrofit {

return Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(
baseClientBuilder
.addInterceptor(AuthInterceptor(tokenManager))
.addInterceptor(AuthInterceptor(context.tokenDataStore))
.build()
)
.build()
Expand Down
22 changes: 15 additions & 7 deletions data/src/main/java/org/gdsc/data/di/TokenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,30 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import org.gdsc.data.datasource.TokenManagerImpl
import org.gdsc.domain.repository.TokenManager
import org.gdsc.data.datasource.TokenDataSource
import org.gdsc.data.datasource.TokenDataSourceImpl
import org.gdsc.data.network.TokenAPI
import org.gdsc.data.repository.TokenRepositoryImpl
import org.gdsc.domain.repository.TokenRepository
import javax.inject.Singleton

val TOKEN_INFO_STORAGE = "token_info_storage"
val Context.tokenDataStore: DataStore<Preferences> by preferencesDataStore(name = TOKEN_INFO_STORAGE)

@Module
@InstallIn(SingletonComponent::class)
class TokenModule {

private val TOKEN_INFO_STORAGE = "token_info_storage"

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = TOKEN_INFO_STORAGE)
@Provides
@Singleton
fun provideTokenDataSource(tokenAPI: TokenAPI): TokenDataSource {
return TokenDataSourceImpl(tokenAPI)
}

@Provides
@Singleton
fun provideTokenManager(@ApplicationContext context: Context): TokenManager {
return TokenManagerImpl(context.dataStore)
fun provideTokenRepository(@ApplicationContext context: Context, tokenDataSource: TokenDataSource): TokenRepository {
return TokenRepositoryImpl(context.tokenDataStore, tokenDataSource)
}

}
17 changes: 14 additions & 3 deletions data/src/main/java/org/gdsc/data/network/Interceptors.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package org.gdsc.data.network

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.stringPreferencesKey
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Response
import org.gdsc.domain.repository.TokenManager
import org.gdsc.domain.Empty
import java.io.IOException
import javax.inject.Inject

Expand All @@ -20,15 +25,21 @@ interface CoroutineInterceptor : Interceptor {
}
}
}

suspend fun interceptSuspend(chain: Interceptor.Chain): Response
}

class AuthInterceptor @Inject constructor(
private val tokenManager: TokenManager
private val dataStore: DataStore<Preferences>,
) : CoroutineInterceptor {

override suspend fun interceptSuspend(chain: Interceptor.Chain): Response {
val token = "Bearer ${tokenManager.getAccessToken()}"

val accessToken = dataStore.data.map { preferences ->
preferences[stringPreferencesKey("accessToken")]
}.first() ?: String.Empty

val token = "Bearer $accessToken"
val newRequest = chain.request().newBuilder()
.addHeader("Authorization", token)
.build()
Expand Down
14 changes: 14 additions & 0 deletions data/src/main/java/org/gdsc/data/network/TokenAPI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.gdsc.data.network

import org.gdsc.data.model.Response
import org.gdsc.domain.model.request.RefreshTokenRequest
import org.gdsc.domain.model.response.TokenResponse
import retrofit2.http.Body
import retrofit2.http.POST

interface TokenAPI {
@POST("api/v1/token")
suspend fun refreshToken(
@Body request: RefreshTokenRequest
): Response<TokenResponse>
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.gdsc.data.datasource
package org.gdsc.data.repository

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
Expand All @@ -7,14 +7,16 @@ import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import org.gdsc.data.datasource.TokenDataSource
import org.gdsc.domain.Empty
import org.gdsc.domain.model.response.TokenResponse
import org.gdsc.domain.repository.TokenManager
import org.gdsc.domain.repository.TokenRepository
import javax.inject.Inject

class TokenManagerImpl @Inject constructor(
private val dataStore: DataStore<Preferences>
): TokenManager {
class TokenRepositoryImpl @Inject constructor(
private val dataStore: DataStore<Preferences>,
private val tokenDataSource: TokenDataSource
) : TokenRepository {


override suspend fun saveTokenInfo(tokenResponse: TokenResponse) {
Expand Down Expand Up @@ -59,6 +61,19 @@ class TokenManagerImpl @Inject constructor(
}
}

// check success or not
override suspend fun requestRefreshToken(refreshToken: String): Boolean {

try {
val newTokenInfo = tokenDataSource.postRefreshToken(refreshToken).data
saveTokenInfo(newTokenInfo)
} catch (e: Exception) {
return false
}

return true
}

companion object {
private val ACCESS_TOKEN = stringPreferencesKey("accessToken")
private val ACCESS_TOKEN_EXPIRES_IN = longPreferencesKey("accessTokenExpiresIn")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.gdsc.domain.model.request

data class RefreshTokenRequest(
val refreshToken: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.gdsc.domain.repository

import org.gdsc.domain.model.response.TokenResponse

interface TokenManager {
interface TokenRepository {

suspend fun saveTokenInfo(tokenResponse: TokenResponse)

Expand All @@ -15,5 +15,7 @@ interface TokenManager {
suspend fun getRefreshToken(): String

suspend fun clearTokenInfo()

suspend fun requestRefreshToken(refreshToken: String): Boolean

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package org.gdsc.domain.usecase.token

import org.gdsc.domain.repository.TokenManager
import org.gdsc.domain.repository.TokenRepository
import javax.inject.Inject

class ClearTokenInfoUseCase @Inject constructor(
private val tokenManager: TokenManager
private val tokenRepository: TokenRepository
) {
suspend operator fun invoke() {
tokenManager.clearTokenInfo()
tokenRepository.clearTokenInfo()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.gdsc.domain.usecase.token

import org.gdsc.domain.repository.TokenManager
import org.gdsc.domain.repository.TokenRepository
import javax.inject.Inject

class GetAccessTokenExpiresInUseCase @Inject constructor(
private val tokenManager: TokenManager
private val tokenRepository: TokenRepository
) {

suspend operator fun invoke(): Long {
return tokenManager.getAccessTokenExpiresIn()
return tokenRepository.getAccessTokenExpiresIn()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.gdsc.domain.usecase.token

import org.gdsc.domain.repository.TokenManager
import org.gdsc.domain.repository.TokenRepository
import javax.inject.Inject

class GetAccessTokenUseCase @Inject constructor(
private val tokenManager: TokenManager
private val tokenRepository: TokenRepository
) {

suspend operator fun invoke(): String {
return tokenManager.getAccessToken()
return tokenRepository.getAccessToken()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.gdsc.domain.usecase.token

import org.gdsc.domain.repository.TokenManager
import org.gdsc.domain.repository.TokenRepository
import javax.inject.Inject

class GetGrantTypeUseCase @Inject constructor(
private val tokenManager: TokenManager
private val tokenRepository: TokenRepository
) {

suspend operator fun invoke(): String {
return tokenManager.getGrantType()
return tokenRepository.getGrantType()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.gdsc.domain.usecase.token

import org.gdsc.domain.repository.TokenManager
import org.gdsc.domain.repository.TokenRepository
import javax.inject.Inject

class GetRefreshTokenUseCase @Inject constructor(
private val tokenManager: TokenManager
private val tokenRepository: TokenRepository
) {

suspend operator fun invoke(): String {
return tokenManager.getRefreshToken()
return tokenRepository.getRefreshToken()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.gdsc.domain.usecase.token

import org.gdsc.domain.repository.TokenRepository
import javax.inject.Inject

class PostRefreshTokenUseCase@Inject constructor(
private val tokenRepository: TokenRepository
) {

suspend operator fun invoke(refreshToken: String): Boolean {
return tokenRepository.requestRefreshToken(refreshToken)
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package org.gdsc.domain.usecase.token

import org.gdsc.domain.model.response.TokenResponse
import org.gdsc.domain.repository.TokenManager
import org.gdsc.domain.repository.TokenRepository
import javax.inject.Inject

class SaveTokenUseCase @Inject constructor(
private val tokenManager: TokenManager,
private val tokenRepository: TokenRepository,
){

suspend operator fun invoke(
response: TokenResponse
) {
tokenManager.saveTokenInfo(response)
tokenRepository.saveTokenInfo(response)

}
}
Loading

0 comments on commit 9c12143

Please sign in to comment.