android - 在改造 android 中使用身份验证器刷新访问令牌
问题描述
如何使用身份验证器刷新我的令牌?当我在我的 api 调用中得到 401 时,我需要刷新令牌方法来返回令牌或 null。
class SupportInterceptor() : Interceptor, Authenticator {
/**
* Interceptor class for setting of the headers for every request
*/
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
request = request?.newBuilder()
?.addHeader("Content-Type", "application/json")
?.addHeader("app-id", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
?.build()
return chain.proceed(request)
}
/**
* Returns a request that includes a credential to satisfy an authentication challenge in
* [response]. Returns null if the challenge cannot be satisfied.
*
* The route is best effort, it currently may not always be provided even when logically
* available. It may also not be provided when an authenticator is re-used manually in an
* application interceptor, such as when implementing client-specific retries.
*/
override fun authenticate(route: Route?, response: Response): Request? {
var requestAvailable: Request? = null
try {
return runBlocking {
when (val tokenResponse = refreshToken()) {
is Success -> {
// userPreferences.saveAccessTokens(
// tokenResponse.value.access_token!!,
// tokenResponse.value.refresh_token!!
// )
response.request.newBuilder()
.header("Authorization", "Bearer ${tokenResponse.value.access_token}")
.build()
}
else -> null
}
}
// requestAvailable = response?.request?.newBuilder()
//// ?.addHeader("Authorization", "Bearer $token")
// ?.build()
// return requestAvailable
} catch (ex: Exception) {
}
return requestAvailable
}
suspend fun refreshToken(): Either<Failure, String?> {
return withContext(Dispatchers.IO) {
try {
val PREFS_NAME = "userPref"
val sharedPref: SharedPreferences =
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val refreshToken = sharedPref.getString(MyConstants.KEY_REFRESH_TOKEN, "")
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val api: TokenRefreshApi = retrofit.create(TokenRefreshApi::class.java)
val response = api.refreshAccessToken(refreshToken).execute()
// val call: Call<LogIn> = api.refreshAccessToken(refreshToken)
when (response.isSuccessful) {
false -> Either.Left(response.errorResponse())
true -> {
val editor: SharedPreferences.Editor = sharedPref.edit()
editor.putString(
MyConstants.KEY_ACCESS_TOKEN,
response.body()!!.access_token
)
editor.putString(
MyConstants.KEY_REFRESH_TOKEN,
response.body()!!.refresh_token
)
editor!!.apply()
response.body()!!.access_token
}
}
} catch (e: Exception) {
Timber.e("searchTasks: $e")
Either.Left(Failure.UnknownError)
}
}
}
}
解决方案
我首先要澄清可靠客户的行业标准行为:
- 客户端尝试使用访问令牌的 API 请求
- 如果客户端收到 401,它会尝试静默刷新访问令牌并使用新令牌重试 API 请求
- 如果存在技术问题,请避免重定向用户以重新进行身份验证
这是我的一些简单的 Kotlin 代码。
在我看来,Retrofit 的 Authenticator 界面让这更容易,并且会为你重试。您的代码看起来大部分正确且与我的相似,但没有手动检查 401:
- 不过,您需要测试 401,一种方法是在开发期间向访问令牌添加任意字符,以模拟到期
推荐阅读
- android - 如何在 Xamarin 中使用无头 WebView
- python - 如何创建一个数据框,其中值来自具有许多变量的函数的结果?熊猫
- asp.net-core - 我们如何在 Cosmosdb(sqlapi) 中使用 Asp.net Core Identity
- php - php数据库连接不能从wordpress函数工作
- salesforce - Salesforce:如何使用顶点代码或公式在日期字段中获取周数(检查第 53 周)
- python-3.x - Python 和递归的新手 - XML 解析
- autohotkey - 如何创建自动热键来控制镜像android中的发布?
- python-3.x - 如何使用一个类创建不同的对象
- nativescript - Nativescript 6 - 点击事件未在子元素上触发
- css - Vuejs:CSS被加载在头部而不是shadow-root