提问人:Nadeem 提问时间:11/10/2023 更新时间:11/10/2023 访问量:19
使用侦听器和身份验证器在令牌过期时创建刷新令牌机制
Creating refresh token mechanism when token is expired using interceptor and authenticator
问:
我想在我的改造请求中创建一个刷新令牌机制,所以如果令牌过期了,我 可以刷新它并调用我使用的 Hilt 依赖注入和改造的相同请求 客户端,当我第一次单击请求时,它正在获取令牌,但我需要再次单击才能使用 我想要相同的点击来做这一切的令牌是我的模块
@Singleton
@Provides
fun providesRetrofitClient(dataStore: DataStore<Preferences>,tokenManager: TokenManager):
AcademicApi {
val mHttpLoggingInterceptor = HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY)
val mOkHttpClient = OkHttpClient
.Builder()
.addInterceptor(mHttpLoggingInterceptor)
.addInterceptor(AuthInterceptorImpl(tokenManager))
.authenticator(Authenticate(tokenManager))
.build()
return Retrofit.Builder()
.baseUrl(ACADEMIC_BASE)
.addConverterFactory(GsonConverterFactory.create(NetworkUtils.gson))
.client(mOkHttpClient)
.build()
.create(AcademicApi::class.java)
}
这是我的令牌管理器代码
class TokenManager @Inject constructor(private val dataStore: DataStore<Preferences>,
private val tokenRepository: TokenRepository){
val username = stringPreferencesKey("username")
val password = stringPreferencesKey("password")
val authToken = stringPreferencesKey("authToken")
val authenticationToken = mutableStateOf("")
private val _getToken = MutableStateFlow<GetToken?>(null)
val getToken: StateFlow<GetToken?> get() = _getToken
val usernameFlow: Flow<String> = dataStore.data
.map { preferences ->
preferences[username] ?: ""
}
@Inject
lateinit var authViewModel: AuthViewModel
val passwordFlow: Flow<String> = dataStore.data
.map { preferences ->
preferences[password] ?: ""
}
val authTokenFlow: Flow<String> = dataStore.data
.map { preferences ->
preferences[authToken] ?: ""
}
val combinedFlow: Flow<Pair<String, String>> = usernameFlow.combine(passwordFlow) {
username, password ->
Pair(username, password)
}
suspend fun saveToken(token: GetToken?) {
val responseData = token
_getToken.emit(responseData)
dataStore.edit { settings ->
settings[authToken] = "Bearer ${responseData?.token.toString()}"
}
}
// Remove the token (e.g., on logout)
suspend fun clearToken() {
dataStore.edit { preferences ->
preferences.remove(authToken)
}
}
// Token refresh logic (you should implement this)
suspend fun refreshToken() {
combinedFlow.collect{ (username,password) ->
val loginRequest = LoginRequest(username,password)
val flow = tokenRepository.getAuthToken(loginRequest)
flow.onCompletion { cause ->
if (cause != null) {
// Handle network errors here*****
}
}
.catch { exception ->
// Handle exceptions here*****
}
.collect { response ->
saveToken(response.data)
// Handle the successful response here
}
}
}
fun getAccessToken(): Flow<String?> {
return dataStore.data.map { preferences ->
preferences[authToken].toString()
}
}
}
这是我的拦截器代码
class AuthInterceptorImpl @Inject constructor(
private val tokenManager: TokenManager
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val acceToken = runBlocking {
tokenManager.getAccessToken().first()
}
val authorizedRequest = originalRequest.newBuilder()
.header("Authorization", acceToken.toString())
.build()
val response = chain.proceed(authorizedRequest)
if (response.code == 401) {
response.close()
Log.e("AuthInterceptor39", "Get WAatt")
val newAccessToken = runBlocking {
tokenManager.refreshToken()
tokenManager.getAccessToken().first()
}
Log.e("AuthInterceptor51", newAccessToken.toString())
val newRequest = originalRequest.newBuilder()
.header("Authorization", "$newAccessToken")
.build()
Log.e("AuthInterceptor55", "Get$newAccessToken")
return chain.proceed(newRequest)
}
return response
}
}
这是我的身份验证器代码
class Authenticate (private val tokenManager: TokenManager,
): Authenticator
{
override fun authenticate(route: Route?, response: Response): Request? {
runBlocking {
tokenManager.refreshToken()
}
return runBlocking {
tokenManager.refreshToken()
val token = tokenManager.getAccessToken().first()
Log.e("AUthenticate22",token.toString())
response.request.newBuilder()
.header("Authorization", token.toString())
.build()
}
}
}
答: 暂无答案
评论