-
Notifications
You must be signed in to change notification settings - Fork 1
DataStore 토큰 저장 기능 구현 & Ktor Token 로직 설정 #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a9a509c
39f7b99
b6df6ad
f40eddc
72331f9
3f53cd7
5696160
773011e
31b2b9b
8d13943
67e6acc
1836194
7e178ac
ce3a138
b4cdeb5
60baa8f
74586fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package com.yapp.twix.di | ||
|
|
||
| import kotlinx.coroutines.CoroutineScope | ||
| import kotlinx.coroutines.Dispatchers | ||
| import kotlinx.coroutines.SupervisorJob | ||
| import org.koin.dsl.module | ||
|
|
||
| val appModule = | ||
| module { | ||
| single<CoroutineScope> { | ||
| CoroutineScope(SupervisorJob() + Dispatchers.IO) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /build |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| plugins { | ||
| alias(libs.plugins.twix.android.library) | ||
| alias(libs.plugins.twix.koin) | ||
| alias(libs.plugins.serialization) | ||
| } | ||
|
|
||
| android { | ||
| namespace = "com.twix.datastore" | ||
| } | ||
|
|
||
| dependencies { | ||
| implementation(projects.core.token) | ||
|
|
||
| implementation(libs.androidx.datastore) | ||
| implementation(libs.kotlinx.serialization.json) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Add project specific ProGuard rules here. | ||
| # You can control the set of applied configuration files using the | ||
| # proguardFiles setting in build.gradle. | ||
| # | ||
| # For more details, see | ||
| # http://developer.android.com/guide/developing/tools/proguard.html | ||
|
|
||
| # If your project uses WebView with JS, uncomment the following | ||
| # and specify the fully qualified class name to the JavaScript interface | ||
| # class: | ||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
| # public *; | ||
| #} | ||
|
|
||
| # Uncomment this to preserve the line number information for | ||
| # debugging stack traces. | ||
| #-keepattributes SourceFile,LineNumberTable | ||
|
|
||
| # If you keep the line number information, uncomment this to | ||
| # hide the original source file name. | ||
| #-renamesourcefileattribute SourceFile |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
|
||
| </manifest> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| package com.twix.datastore | ||
|
|
||
| import androidx.datastore.core.Serializer | ||
| import kotlinx.coroutines.Dispatchers | ||
| import kotlinx.coroutines.withContext | ||
| import kotlinx.serialization.Serializable | ||
| import kotlinx.serialization.SerializationException | ||
| import kotlinx.serialization.json.Json | ||
| import java.io.InputStream | ||
| import java.io.OutputStream | ||
|
|
||
| @Serializable | ||
| internal data class AuthConfigure( | ||
| val accessToken: String = | ||
| "eyJhbGciOiJIUzM4NCJ9." + | ||
| "eyJzdWIiOiIxIiwidHlwZSI6ImFjY2VzcyIsImlhdCI6MTc3MDI0NzM0NCwiZXhwIjoxNzcwODUyMTQ0fQ." + | ||
| "67rDscm8BeayYFA1gfcEMliEdEh8-HTUyE5TwmAT8Ef8ZvtaWczxpMNZqI5htiek", | ||
| val refreshToken: String = | ||
| "eyJhbGciOiJIUzM4NCJ9." + | ||
| "eyJzdWIiOiIxIiwidHlwZSI6InJlZnJlc2giLCJpYXQiOjE3NzAyNDczNDQsImV4cCI6MTc3MDg1MjE0NH0." + | ||
| "zgUYdR6onyeY5EaH2_pWLs1rjNLf8m8ZeXsY7Cbk99a_2tzR0rDBZO_hdGTnorRL", | ||
| ) | ||
|
|
||
| internal object AuthConfigureSerializer : Serializer<AuthConfigure> { | ||
| private val json = | ||
| Json { | ||
| ignoreUnknownKeys = true | ||
| isLenient = true | ||
| } | ||
|
|
||
| override val defaultValue: AuthConfigure | ||
| get() = AuthConfigure() | ||
|
|
||
| override suspend fun readFrom(input: InputStream): AuthConfigure = | ||
| try { | ||
| withContext(Dispatchers.IO) { | ||
| json.decodeFromString( | ||
| deserializer = AuthConfigure.serializer(), | ||
| string = input.readBytes().decodeToString(), | ||
| ) | ||
| } | ||
| } catch (e: SerializationException) { | ||
| defaultValue | ||
| } | ||
|
Comment on lines
+34
to
+44
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기에서는 IO 디스패처를 사용하지 않는 이유가 있나요?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앗.. 단순 실수 ^_^... 꼼꼼하게 봐줘서 고마워 ! 리뷰 반영 커밋 : 31b2b9b |
||
|
|
||
| override suspend fun writeTo( | ||
| t: AuthConfigure, | ||
| output: OutputStream, | ||
| ) { | ||
| withContext(Dispatchers.IO) { | ||
| output.write( | ||
| json | ||
| .encodeToString( | ||
| serializer = AuthConfigure.serializer(), | ||
| value = t, | ||
| ).encodeToByteArray(), | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 토큰을 매번 처음부터 읽지 않고 StateIn 사용해서 StateFlow로 캐싱하면 더 좋을 거 같아요! stateIn 쓰려면 스코프가 있어야 하는데 Koin으로 주입받거나 내부에서 SupervisorJob 기반으로 스코프 만들어서 쓰면 될 것 같습니다.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이미 만들어두신 AuthConfigure 사용해도 되고 이런 거 추가해서 캐싱할 때 access, refresh 둘 다 들고 있으면 두번 읽지 않게 구현할 수 있을 것 같아요 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package com.twix.datastore | ||
|
|
||
| import android.content.Context | ||
| import androidx.datastore.core.DataStore | ||
| import com.twix.token.TokenProvider | ||
| import kotlinx.coroutines.CoroutineScope | ||
| import kotlinx.coroutines.flow.SharingStarted | ||
| import kotlinx.coroutines.flow.stateIn | ||
|
|
||
| class AuthTokenProvider( | ||
| context: Context, | ||
| scope: CoroutineScope, | ||
| ) : TokenProvider { | ||
| private val dataStore: DataStore<AuthConfigure> = context.authDataStore | ||
|
|
||
| private val tokenState = | ||
| dataStore.data | ||
| .stateIn( | ||
| scope = scope, | ||
| started = SharingStarted.Eagerly, | ||
| initialValue = AuthConfigure(), | ||
| ) | ||
|
|
||
| override val accessToken: String | ||
| get() = tokenState.value.accessToken | ||
|
|
||
| override val refreshToken: String | ||
| get() = tokenState.value.refreshToken | ||
|
|
||
chanho0908 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| override suspend fun saveToken( | ||
| accessToken: String, | ||
| refreshToken: String, | ||
| ) { | ||
| dataStore.updateData { | ||
| it.copy(accessToken = accessToken, refreshToken = refreshToken) | ||
| } | ||
| } | ||
|
|
||
| override suspend fun clear() { | ||
| dataStore.updateData { | ||
| it.copy(accessToken = "", refreshToken = "") | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.twix.datastore | ||
|
|
||
| import android.content.Context | ||
| import androidx.datastore.core.DataStore | ||
| import androidx.datastore.dataStore | ||
|
|
||
| internal val Context.authDataStore: DataStore<AuthConfigure> by dataStore( | ||
| fileName = "auth-configure.json", | ||
| serializer = AuthConfigureSerializer, | ||
| ) | ||
chanho0908 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.twix.datastore.di | ||
|
|
||
| import android.content.Context | ||
| import com.twix.datastore.AuthTokenProvider | ||
| import com.twix.token.TokenProvider | ||
| import kotlinx.coroutines.CoroutineScope | ||
| import org.koin.dsl.module | ||
|
|
||
| val dataStoreModule = | ||
| module { | ||
| single<TokenProvider> { AuthTokenProvider(get<Context>(), get<CoroutineScope>()) } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.twix.network.model.request | ||
|
|
||
| import kotlinx.serialization.Serializable | ||
|
|
||
| @Serializable | ||
| data class LoginRequest( | ||
| val code: String, | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.twix.network.model.request | ||
|
|
||
| import kotlinx.serialization.Serializable | ||
|
|
||
| @Serializable | ||
| data class RefreshRequest( | ||
| val refreshToken: String, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Json 인스턴스를 매번 생성하지 말고 미리 선언해놓고 사용하면 좋을 거 같아요! 보통 Json 미리 만들어 둘 때
이렇게 모르는 키는 무시해서 Exception 발생 안하게 하기도 해요. 추가 설정 필요한 거 있으면 더 추가해도 됩니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 생각인거 같아 !
리뷰 반영 커밋 : https://github.com/YAPP-Github/Twix-
Android/pull/59/commits/773011e5c9b140d39d62bdeb77f9e6d436d30c69