dm-191
This commit is contained in:
parent
bf26416238
commit
3680968689
1 changed files with 24 additions and 15 deletions
|
|
@ -1,22 +1,21 @@
|
||||||
package com.example.login_v3.data.repository.basic
|
package com.example.login_v3.data.repository.basic
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.datastore.core.DataStore
|
import androidx.datastore.core.DataStore
|
||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
|
||||||
import androidx.datastore.preferences.core.edit
|
import androidx.datastore.preferences.core.edit
|
||||||
import androidx.datastore.preferences.core.longPreferencesKey
|
import androidx.datastore.preferences.core.longPreferencesKey
|
||||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
import androidx.datastore.preferences.core.stringSetPreferencesKey
|
import androidx.datastore.preferences.core.stringSetPreferencesKey
|
||||||
import com.example.login_v3.data.api.RefreshRequest
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
|
||||||
class TokenManager @Inject constructor(
|
class TokenManager @Inject constructor(
|
||||||
private val dataStore: DataStore<Preferences>
|
private val dataStore: DataStore<Preferences>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val allUserIds: Flow<Set<String>> = dataStore.data.map { preferences ->
|
val allUserIds: Flow<Set<String>> = dataStore.data.map { preferences ->
|
||||||
preferences[USER_ID_LIST] ?: emptySet()
|
preferences[USER_ID_LIST] ?: emptySet()
|
||||||
}
|
}
|
||||||
|
|
@ -25,19 +24,17 @@ class TokenManager @Inject constructor(
|
||||||
private val USER_ID_LIST = stringSetPreferencesKey("user_id_list")
|
private val USER_ID_LIST = stringSetPreferencesKey("user_id_list")
|
||||||
private val CURRENT_USER_ID = stringPreferencesKey("current_user_id")
|
private val CURRENT_USER_ID = stringPreferencesKey("current_user_id")
|
||||||
|
|
||||||
// 動態生成每個 User 專屬的 Key
|
|
||||||
private fun accessTokenKey(userId: String) = stringPreferencesKey("access_token_$userId")
|
private fun accessTokenKey(userId: String) = stringPreferencesKey("access_token_$userId")
|
||||||
private fun refreshTokenKey(userId: String) = stringPreferencesKey("refresh_token_$userId")
|
private fun refreshTokenKey(userId: String) = stringPreferencesKey("refresh_token_$userId")
|
||||||
private fun expiresAtKey(userId: String) = longPreferencesKey("expires_at_$userId")
|
private fun expiresAtKey(userId: String) = longPreferencesKey("expires_at_$userId")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 儲存特定使用者的完整 Auth 資料(新增了 refreshToken 與 expiresIn)
|
// 儲存資料(維持原樣,這是安全的)
|
||||||
suspend fun saveAuthData(userId: String, accessToken: String, refreshToken: String, expiresInSec: Int) {
|
suspend fun saveAuthData(userId: String, accessToken: String, refreshToken: String, expiresInSec: Int) {
|
||||||
dataStore.edit { preferences ->
|
dataStore.edit { preferences ->
|
||||||
preferences[accessTokenKey(userId)] = accessToken
|
preferences[accessTokenKey(userId)] = accessToken
|
||||||
preferences[refreshTokenKey(userId)] = refreshToken
|
preferences[refreshTokenKey(userId)] = refreshToken
|
||||||
|
|
||||||
// 計算絕對過期時間戳記:當前時間(毫秒)+ 有效秒數 * 1000
|
|
||||||
val expiresAt = System.currentTimeMillis() + (expiresInSec * 1000L)
|
val expiresAt = System.currentTimeMillis() + (expiresInSec * 1000L)
|
||||||
preferences[expiresAtKey(userId)] = expiresAt
|
preferences[expiresAtKey(userId)] = expiresAt
|
||||||
|
|
||||||
|
|
@ -50,16 +47,28 @@ class TokenManager @Inject constructor(
|
||||||
|
|
||||||
val currentUserId: Flow<String?> = dataStore.data.map { it[CURRENT_USER_ID] }
|
val currentUserId: Flow<String?> = dataStore.data.map { it[CURRENT_USER_ID] }
|
||||||
|
|
||||||
// 獲取當前帳號的 Access Token
|
// 🌟 核心修正一:提供一個可以直接傳入 userId 獲取 Token 的 suspend 函式
|
||||||
val currentAccessToken: Flow<String?> = dataStore.data.map { preferences ->
|
// 這樣在 Authenticator 內,當你已經有 currentUserId 時,直接用這個抓最安全!
|
||||||
val userId = preferences[CURRENT_USER_ID] ?: return@map null
|
suspend fun getAccessToken(userId: String): String? {
|
||||||
|
return dataStore.data.map { preferences ->
|
||||||
preferences[accessTokenKey(userId)]
|
preferences[accessTokenKey(userId)]
|
||||||
|
}.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 💡 新增:獲取當前帳號的 Refresh Token(供 Authenticator 使用)
|
// 🌟 核心修正二:改用 flatMapLatest (需要 import kotlinx.coroutines.flow.flatMapLatest)
|
||||||
val currentRefreshToken: Flow<String?> = dataStore.data.map { preferences ->
|
// 確保當 CURRENT_USER_ID 改變時,舊的 Flow 會被立即取消並重導向,防止讀到髒資料
|
||||||
val userId = preferences[CURRENT_USER_ID] ?: return@map null
|
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
|
||||||
preferences[refreshTokenKey(userId)]
|
val currentAccessToken: Flow<String?> = currentUserId.flatMapLatest { userId ->
|
||||||
|
dataStore.data.map { preferences ->
|
||||||
|
if (userId == null) null else preferences[accessTokenKey(userId)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
|
||||||
|
val currentRefreshToken: Flow<String?> = currentUserId.flatMapLatest { userId ->
|
||||||
|
dataStore.data.map { preferences ->
|
||||||
|
if (userId == null) null else preferences[refreshTokenKey(userId)]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切換帳號、登出等邏輯保持不變,但登出時記得一併移除 refresh_token 與 expires_at
|
// 切換帳號、登出等邏輯保持不變,但登出時記得一併移除 refresh_token 與 expires_at
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue