Skip to content

Commit

Permalink
Merge pull request #206 from GSM-MSG/refactor/#204_update_token_fucti…
Browse files Browse the repository at this point in the history
…on_logic

🔀 :: (#204) AuthTokenDataSource의 함수 수정
  • Loading branch information
Chaejongin12 authored Jun 3, 2024
2 parents d687748 + 1e7979d commit 37cc22e
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import com.msg.model.remote.request.auth.SignUpJobClubTeacherRequest
import com.msg.model.remote.request.auth.SignUpProfessorRequest
import com.msg.model.remote.request.auth.SignUpStudentRequest
import com.msg.network.datasource.auth.AuthDataSource
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
Expand Down
100 changes: 38 additions & 62 deletions core/datastore/src/main/java/com/msg/datastore/AuthTokenDataSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,92 +4,68 @@ import Authority
import androidx.datastore.core.DataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.transform
import java.time.LocalDateTime
import javax.inject.Inject

class AuthTokenDataSource @Inject constructor(
private val authToken: DataStore<AuthToken>,
) {
fun getAccessToken(): Flow<String> = authToken.data.map {
it.accessToken ?: ""
}

fun setAccessToken(accessToken: String): Flow<Unit> = flow {
authToken.updateData {
it.toBuilder()
.setAccessToken(accessToken)
.build()
fun getAccessToken(): Flow<String> = authToken.data
.transform { data ->
emit(data.accessToken ?: "")
}
emit(Unit)

fun setAccessToken(accessToken: String): Flow<Unit> {
return updateAuthToken { it.toBuilder().setAccessToken(accessToken).build() }
}

fun getAccessTokenExp(): Flow<LocalDateTime> =
authToken.data.mapNotNull { it.accessExp }.map { accessExp ->
LocalDateTime.parse(accessExp)
fun getAccessTokenExp(): Flow<LocalDateTime> = authToken.data
.transform { data ->
data.accessExp?.let {
emit(LocalDateTime.parse(it))
}
}

fun setAccessTokenExp(accessTokenExp: String): Flow<Unit> {
return updateAuthToken { it.toBuilder().setAccessExp(accessTokenExp).build() }
}

fun setAccessTokenExp(accessTokenExp: String): Flow<Unit> = flow {
authToken.updateData {
it.toBuilder()
.setAccessExp(accessTokenExp)
.build()
fun getRefreshToken(): Flow<String> = authToken.data
.transform { data ->
emit(data.refreshToken ?: "")
}
emit(Unit)
}

fun getRefreshToken(): Flow<String> = authToken.data.map {
it.refreshToken ?: ""
fun setRefreshToken(refreshToken: String): Flow<Unit> {
return updateAuthToken { it.toBuilder().setRefreshToken(refreshToken).build() }
}

fun setRefreshToken(refreshToken: String): Flow<Unit> = flow {
authToken.updateData {
it.toBuilder()
.setRefreshToken(refreshToken)
.build()
fun getRefreshTokenExp(): Flow<LocalDateTime> = authToken.data
.transform { data ->
data.refreshExp?.let {
emit(LocalDateTime.parse(it))
}
}
emit(Unit)
}

fun getRefreshTokenExp(): Flow<LocalDateTime> =
authToken.data.mapNotNull { it.refreshExp?.let { refreshExp ->
LocalDateTime.parse(refreshExp)
} }


fun setRefreshTokenExp(refreshTokenExp: String): Flow<Unit> = flow {
authToken.updateData {
it.toBuilder()
.setRefreshExp(refreshTokenExp)
.build()
}
fun setRefreshTokenExp(refreshTokenExp: String): Flow<Unit> {
return updateAuthToken { it.toBuilder().setRefreshExp(refreshTokenExp).build() }
}

fun getAuthority(): Flow<Authority> = authToken.data.mapNotNull { data ->
data.authority?.let { authority ->
when (authority) {
"ROLE_USER" -> Authority.ROLE_USER
"ROLE_ADMIN" -> Authority.ROLE_ADMIN
"ROLE_STUDENT" -> Authority.ROLE_STUDENT
"ROLE_TEACHER" -> Authority.ROLE_TEACHER
"ROLE_BBOZZAK" -> Authority.ROLE_BBOZZAK
"ROLE_PROFESSOR" -> Authority.ROLE_PROFESSOR
"ROLE_COMPANY_INSTRUCTOR" -> Authority.ROLE_COMPANY_INSTRUCTOR
"ROLE_GOVERNMENT" -> Authority.ROLE_GOVERNMENT
else -> null
fun getAuthority(): Flow<Authority> = authToken.data
.transform { data ->
data.authority?.let { authority ->
Authority.entries.firstOrNull { it.name == authority }?.let {
emit(it)
}
}
}
}

fun setAuthority(authority: Authority): Flow<Unit> {
return updateAuthToken { it.toBuilder().setAuthority(authority.name).build() }
}

fun setAuthority(authority: Authority): Flow<Unit> = flow {
authToken.updateData {
it.toBuilder()
.setAuthority(authority.toString())
.build()
}
private fun updateAuthToken(update: (AuthToken) -> AuthToken): Flow<Unit> = flow {
authToken.updateData { update(it) }
emit(Unit)
}
}
62 changes: 26 additions & 36 deletions core/network/src/main/java/com/msg/network/util/AuthInterceptor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import java.time.LocalDateTime
import javax.inject.Inject

class AuthInterceptor @Inject constructor(
Expand All @@ -35,53 +34,44 @@ class AuthInterceptor @Inject constructor(


runBlocking {
val refreshTime = dataSource.getRefreshTokenExp().toString()
val accessTime = dataSource.getAccessTokenExp().toString()
val refreshTime = dataSource.getRefreshTokenExp().first()
val accessTime = dataSource.getAccessTokenExp().first()
val accessToken = dataSource.getAccessToken().first()
val refreshToken = dataSource.getRefreshToken().first()

if (refreshTime == "") {
if (refreshTime.toString() == "") {
return@runBlocking
}

if (currentTime != null) {
if (currentTime.isAfter(refreshTime.toLocalDateTime())) {
throw NeedLoginException()
}
if (currentTime != null && currentTime.isAfter(refreshTime.toLocalDateTime())) {
throw NeedLoginException()
}

//Re Issue Access Token
if (currentTime != null) {
if (currentTime.isAfter(accessTime.toLocalDateTime())) {
val client = OkHttpClient()
val refreshRequest = Request.Builder()
.url(BuildConfig.BASE_URL + "auth")
.patch(chain.request().body ?: RequestBody.Companion.create(null, byteArrayOf()))
.addHeader(
"RefreshToken",
dataSource.getRefreshToken().toString()
)
.build()
val jsonParser = JsonParser()
val response = client.newCall(refreshRequest).execute()
if (response.isSuccessful) {
val token = jsonParser.parse(response.body!!.string()) as JsonObject
dataSource.setAccessToken(token["accessToken"].toString()).first()
dataSource.setAccessTokenExp(token["accessExpiration"].toString()).first()
dataSource.setRefreshToken(token["refreshToken"].toString()).first()
dataSource.setRefreshTokenExp(token["refreshExpiration"].toString()).first()
} else throw NeedLoginException()
}
if (currentTime != null && currentTime.isAfter(accessTime.toLocalDateTime())) {
val client = OkHttpClient()
val refreshRequest = Request.Builder()
.url(BuildConfig.BASE_URL + "auth")
.patch(chain.request().body ?: RequestBody.Companion.create(null, byteArrayOf()))
.addHeader("RefreshToken", "Bearer $refreshToken")
.build()

val jsonParser = JsonParser()
val response = client.newCall(refreshRequest).execute()
if (response.isSuccessful) {
val token = jsonParser.parse(response.body!!.string()) as JsonObject
dataSource.setAccessToken(token["accessToken"].toString()).first()
dataSource.setAccessTokenExp(token["accessExpiration"].toString()).first()
dataSource.setRefreshToken(token["refreshToken"].toString()).first()
dataSource.setRefreshTokenExp(token["refreshExpiration"].toString()).first()
} else throw NeedLoginException()
} else {
builder.addHeader("Authorization", "Bearer $accessToken")
}
val accessToken = dataSource.getAccessToken().first()
val refreshToken = dataSource.getRefreshToken().first()
if (method == "DELETE") {
builder.addHeader("RefreshToken", "Bearer $refreshToken")
}
builder.addHeader("Authorization", "Bearer $accessToken")
}
return chain.proceed(builder.build())
}
}

fun LocalDateTime.isAfter(compare: LocalDateTime): Boolean {
return this > compare
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
package com.msg.network.util

import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException

fun Any?.toLocalDateTime(): LocalDateTime? {
val dateString = this?.toString()
if (dateString != null) {
return try {
LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-d'T'HH:mm:ss"))
return when {
dateString == null -> null
else -> try {
when {
dateString.matches(Regex("\\d{13}")) -> { // Milliseconds -> LocalDateTime 처리
LocalDateTime.ofInstant(Instant.ofEpochMilli(dateString.toLong()), ZoneId.systemDefault())
}
dateString.contains('.') -> { // 나노초를 포함한 경우 나노초 제거
val trimmedDateString = dateString.substring(0, dateString.indexOf('.'))
LocalDateTime.parse(trimmedDateString, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))
}
else -> { // 나노초를 포함하지 않은 경우
LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))
}
}
} catch (e: DateTimeParseException) {
e.printStackTrace()
null
} catch (e: NumberFormatException) {
e.printStackTrace()
null
}
}
return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.lifecycle.viewModelScope
import com.bitgoeul.login.viewmodel.util.Event
import com.bitgoeul.login.viewmodel.util.errorHandling
import com.msg.domain.auth.LoginUseCase
import com.msg.domain.auth.LogoutUseCase
import com.msg.domain.auth.SaveTokenUseCase
import com.msg.model.remote.model.auth.AuthTokenModel
import com.msg.model.remote.request.auth.LoginRequest
Expand All @@ -19,11 +18,10 @@ import javax.inject.Inject
@HiltViewModel
class AuthViewModel @Inject constructor(
private val loginUseCase: LoginUseCase,
private val logoutUseCase: LogoutUseCase,
private val saveTokenUseCase: SaveTokenUseCase,
) : ViewModel() {
private val _saveTokenRequest = MutableStateFlow<Event<Nothing>>(Event.Loading)
val saveTokenRequest = _saveTokenRequest.asStateFlow()
private val _saveTokenResponse = MutableStateFlow<Event<Nothing>>(Event.Loading)
val saveTokenRequest = _saveTokenResponse.asStateFlow()

private val _loginResponse = MutableStateFlow<Event<AuthTokenModel>>(Event.Loading)
val loginResponse = _loginResponse.asStateFlow()
Expand All @@ -49,9 +47,13 @@ class AuthViewModel @Inject constructor(
saveTokenUseCase(
data = data
).onSuccess {
_saveTokenRequest.value = Event.Success()
it.catch { remoteError ->
_saveTokenResponse.value = remoteError.errorHandling()
}.collect {
_saveTokenResponse.value = Event.Success()
}
}.onFailure {
_saveTokenRequest.value = it.errorHandling()
_saveTokenResponse.value = it.errorHandling()
}
}
}

0 comments on commit 37cc22e

Please sign in to comment.