fre*_*yle 5 android android-authenticator retrofit okhttp refresh-token
我想在访问令牌过期时刷新它。我已经实现了 Authenticator,如下所示:
@Singleton
class TokenAuthenticator(
val authService: Lazy<AuthService>,
private val sharedPreferences: SharedPreferences
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
return authRequestWithNewToken(response.request)
}
private fun authRequestWithNewToken(
request: Request
): Request? {
getFreshAccessToken()?.let { freshToken ->
return getNewRequest(request, freshToken)
}
return null
}
private fun getFreshAccessToken(): String? {
val refreshResponse = authService.get().refreshTokenTemp().execute()
if (refreshResponse.isSuccessful) {
val updatedAccessToken =
refreshResponse.body()?.data?.accessToken ?: return null
val updatedRefreshToken =
refreshResponse.body()?.data?.refreshToken ?: return null
updateToken(updatedAccessToken, updatedRefreshToken)
Timber.tag("TOKEN")
.d("Auth Updated token\n AccessToken: $updatedAccessToken \n RefreshToken: $updatedRefreshToken")
return updatedAccessToken
} else {
return null
}
}
private fun getNewRequest(request: Request, accessToken: String): Request {
return request.newBuilder()
.header(
AppConstants.PARAMS.AUTH,
AppConstants.PARAMS.BEARER + accessToken
)
.header("Accept", "application/json")
.header("User-Agent", AppConstants.PARAMS.USER_AGENT)
.build()
}
private fun updateToken(accessToken: String, refreshToken: String) {
with(sharedPreferences.edit()) {
putString(AppConstants.SHAREDPREFERENCE.ACCESS_TOKEN, accessToken)
putString(AppConstants.SHAREDPREFERENCE.REFRESH_TOKEN, refreshToken).apply()
}
AppVariables.SessionData.accessToken = accessToken
AppVariables.SessionData.refreshToken = refreshToken
Timber.tag("TOKEN").d("Token Refreshed")
}
}
Run Code Online (Sandbox Code Playgroud)
即使使用此功能后,由于发生并行 API 调用,我的应用程序仍然超时,并且用户被带到登录屏幕。
即使花了很多时间我也无法弄清楚出了什么问题。
我看到人们在尝试@synchronised,我也尝试实施,但没有成功。
最后我看到他添加了一个这样的调度程序:
@Singleton
@Provides
fun provideOkhttpClient(tokenAuthenticator: TokenAuthenticator): OkHttpClient {
//***********like this**********************//
val dispatcher = Dispatcher()
dispatcher.maxRequests = 1
//******************************************//
return OkHttpClient.Builder()
.dispatcher(dispatcher)
.connectTimeout(180, TimeUnit.SECONDS)
.readTimeout(180, TimeUnit.SECONDS)
.writeTimeout(180, TimeUnit.SECONDS)
.authenticator(tokenAuthenticator)
.addInterceptor(TokenInterceptor())
.build()
}
Run Code Online (Sandbox Code Playgroud)
这似乎解决了我的问题。但是,我不知道这意味着什么。是否建议在生产中使用?
我可以在文档中看到以下内容:
并发执行的最大请求数。此请求在内存中排队,等待正在运行的调用完成。如果在调用此函数时有超过 maxRequests 个请求正在处理中,则这些请求将保持在处理中。
我是否错过了一些可能会在以后咬我屁股的东西?
要求是同步刷新尝试,以确保来自视图模型的所有正在进行的 API 请求获得相同的(旋转的)刷新令牌响应。因此,一个视图模型发出请求,而所有其他视图模型则在工作线程上等待。
一种方法是像我的这段代码一样对延续进行排队。这使您能够编写这样的代码,仅发送一次 HTTP 请求。在你的例子中,OkHttp 调度程序似乎在做同样的工作,所以感觉走在正确的轨道上。
override suspend fun refreshAccessToken(): String {
return this.concurrencyHandler.execute(this::performRefreshTokenGrant)
}
Run Code Online (Sandbox Code Playgroud)
为了确保行为正确,您应该测试到期事件。首先,我将跟踪 HTTP(S) 流量并验证刷新请求是否仅触发一次。还要测试多个刷新请求是否可以相继运行。通过本地开发选项向访问令牌添加字符以使其表现为过期,模拟访问令牌过期非常容易。您可以运行我的代码示例来查看该方法。
| 归档时间: |
|
| 查看次数: |
604 次 |
| 最近记录: |