auth to server-V90
This commit is contained in:
parent
b843518d8b
commit
321be95ff0
4 changed files with 52 additions and 13 deletions
|
|
@ -77,7 +77,7 @@ fun LoginScreen(
|
|||
|
||||
|
||||
|
||||
|
||||
//background
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@ import com.example.login_v3.data.repository.basic.AuthRepository
|
|||
import com.example.login_v3.data.repository.basic.TokenManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -23,12 +25,20 @@ sealed class LoginUiState {
|
|||
@HiltViewModel
|
||||
class AuthViewModel @Inject constructor(
|
||||
private val repository: AuthRepository,
|
||||
private val tokenManager: TokenManager // 注入 TokenManager
|
||||
private val tokenManager: TokenManager
|
||||
) : ViewModel() {
|
||||
|
||||
private val _loginState = MutableStateFlow<LoginUiState>(LoginUiState.Idle)
|
||||
val loginState: StateFlow<LoginUiState> = _loginState.asStateFlow()
|
||||
|
||||
// --- 新增:供 UI 顯示所有已登入帳號與當前帳號 ---
|
||||
val allUserIds: StateFlow<Set<String>> = tokenManager.allUserIds
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptySet())
|
||||
|
||||
val currentUserId: StateFlow<String?> = tokenManager.currentUserId
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)
|
||||
// ------------------------------------------
|
||||
|
||||
fun login(username: String, password: String) {
|
||||
viewModelScope.launch {
|
||||
_loginState.value = LoginUiState.Loading
|
||||
|
|
@ -39,10 +49,15 @@ class AuthViewModel @Inject constructor(
|
|||
if (response.isSuccessful && response.body() != null) {
|
||||
val loginResponse = response.body()!!
|
||||
|
||||
// 1. 先把 Token 存入 DataStore
|
||||
tokenManager.saveAuthData(loginResponse.access_token)
|
||||
// 修改:存入 token 時同時存入 userId (假設你的 user 物件裡有 id)
|
||||
// 如果 LoginResponse 沒給 id,也可以用 username 作為唯一識別碼
|
||||
val userId = loginResponse.user.id.toString()
|
||||
|
||||
tokenManager.saveAuthData(
|
||||
userId = userId,
|
||||
token = loginResponse.access_token
|
||||
)
|
||||
|
||||
// 2. 更新 UI 狀態
|
||||
_loginState.value = LoginUiState.Success(loginResponse.user)
|
||||
} else {
|
||||
_loginState.value = LoginUiState.Error("登入失敗:${response.code()}")
|
||||
|
|
@ -52,4 +67,19 @@ class AuthViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 新增:切換帳號功能 ---
|
||||
fun switchAccount(userId: String) {
|
||||
viewModelScope.launch {
|
||||
tokenManager.switchAccount(userId)
|
||||
// 切換後,通常會需要重新初始化某些頁面資料,或發送一個事件通知 UI
|
||||
}
|
||||
}
|
||||
|
||||
// --- 新增:登出功能 ---
|
||||
fun logout(userId: String) {
|
||||
viewModelScope.launch {
|
||||
tokenManager.logout(userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,20 +46,30 @@ object NetworkModule {
|
|||
@Singleton
|
||||
fun provideOkHttpClient(tokenManager: TokenManager): OkHttpClient {
|
||||
return OkHttpClient.Builder()
|
||||
.connectTimeout(15, TimeUnit.SECONDS) // 連線逾時
|
||||
.readTimeout(15, TimeUnit.SECONDS) // 讀取逾時
|
||||
.connectTimeout(15, TimeUnit.SECONDS)
|
||||
.readTimeout(15, TimeUnit.SECONDS)
|
||||
.addInterceptor { chain ->
|
||||
val token = runBlocking { tokenManager.accessToken.first() }
|
||||
val requestBuilder = chain.request().newBuilder()
|
||||
// 1. 動態獲取「目前選中帳號」的 Token
|
||||
// 使用 first() 確保只取目前最新的那一個值
|
||||
val token = runBlocking { tokenManager.currentAccessToken.first() }
|
||||
|
||||
val requestBuilder = chain.request().newBuilder()
|
||||
token?.let {
|
||||
requestBuilder.addHeader("Authorization", "Bearer $it")
|
||||
}
|
||||
|
||||
val response = chain.proceed(requestBuilder.build())
|
||||
|
||||
// 2. 處理 Token 失效 (401)
|
||||
if (response.code == 401) {
|
||||
runBlocking { tokenManager.clearAuthData() }
|
||||
runBlocking {
|
||||
// 獲取目前是哪個 ID 失效了
|
||||
val currentId = tokenManager.currentUserId.first()
|
||||
currentId?.let {
|
||||
// 只登出當前失效的帳號,不影響其他帳號
|
||||
tokenManager.logout(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response
|
||||
|
|
|
|||
|
|
@ -20,11 +20,10 @@ class TokenManager @Inject constructor(
|
|||
preferences[USER_ID_LIST] ?: emptySet()
|
||||
}
|
||||
|
||||
// TokenManager 內部建議改動
|
||||
companion object {
|
||||
// 1. 記錄目前正在使用的 UserId
|
||||
private val USER_ID_LIST = stringSetPreferencesKey("user_id_list") // 移到這裡
|
||||
private val CURRENT_USER_ID = stringPreferencesKey("current_user_id")
|
||||
|
||||
// 2. 輔助函式:根據 userId 動態產生 Token 的 Key
|
||||
private fun accessTokenKey(userId: String) = stringPreferencesKey("access_token_$userId")
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue