У меня есть приложение Android с модифицированным клиентом и перехватчиком, которое проверяет код ответа 401 (срок действия токена истек), поэтому после обнаружения этой ошибки я могу выполнить другую веб-службу, которая обновит sh мой токен, используя токен refre sh, предоставленный мне, когда я вошел в систему, и все это работает хорошо и плавно.
Моя проблема в том, как отозвать первый запрос после получения нового действительного токена и его сохранения.
class AuthenticationInterceptorRefreshToken(var client: OkHttpClient?, var retrofit: Retrofit?) :
Interceptor {
private val TAG = "AuthenticationIntercept"
var authenticationUseCase = AuthenticationUseCase()
@SuppressLint("CheckResult")
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val builder = request.newBuilder()
request = builder.build()
val response = chain.proceed(request)
if (response.code() == 401) {
Log.e(TAG, "intercept: Refresh it")
if (Paper.book().contains(Const.USER_CONNECTED)) {
val currentToken: String =
(Paper.book().read(Const.USER_CONNECTED) as LoginResponse).refreshToken
authenticationUseCase.refreshToken(RefreshTokenRequest(currentToken))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
when (it) {
is AuthenticationUseCase.LoginResult.Success -> {
val new =
(Paper.book().read(Const.USER_CONNECTED) as LoginResponse)
val gson = Gson()
val data = gson.fromJson(
gson.toJson(it.userResponse.data),
NewTokenResponse::class.java
)
new.token = data.token
Paper.book().write(Const.USER_CONNECTED, new)
Log.e(TAG, "handleRefreshToken Success New: $new")
//todo re-execute the web service
}
is AuthenticationUseCase.LoginResult.Failure -> {
Log.e(
TAG,
"handleRefreshToken Failure: ${it.throwable.localizedMessage}"
)
logout()
}
}
}, {
Log.e(TAG, "intercept: Here something BAD: $it")
})
return response
} else {
Log.e(TAG, "intercept No data found: ")
context.startActivity(
Intent(
context,
WelcomingActivity::class.java
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
}
return response
}
return response
}
@SuppressLint("CheckResult")
private fun logout() {
authenticationUseCase.logout(
LogoutRequest(
(Paper.book().read(Const.USER_CONNECTED) as LoginResponse).user.id,
(Paper.book().read(Const.USER_CONNECTED) as LoginResponse).refreshToken
)
).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
when (it) {
is AuthenticationUseCase.LoginResult.Success -> {
Log.e(TAG, "showLogoutDialog: Success: ${it.userResponse}")
Paper.book().delete(Const.USER_CONNECTED)
GlobalUtils.navigateToActivity(
context as Activity,
context,
WelcomingActivity::class.java
)
}
is AuthenticationUseCase.LoginResult.Failure -> {
if (it.throwable.localizedMessage.contains("500")) {
Log.e(TAG, "getConnectedUser: Problem here 2")
Toast.makeText(context, "Server error...", Toast.LENGTH_LONG)
.show()
}
Log.e(TAG, "showLogoutDialog: Failure: ${it.throwable}")
}
}
}
}
}
И это мой модифицированный клиент, который я использую при каждом обращении к серверу
object RetrofitClient {
private var retrofit: Retrofit? = null
private var client: OkHttpClient? = null
fun build(): ItchekApi {
if (retrofit == null) {
if (client == null)
client = OkHttpClient.Builder()
.addInterceptor(
AuthenticationInterceptorRefreshToken(
client,
retrofit
)
)
.addInterceptor(HeaderInterceptor())
.connectTimeout(100, TimeUnit.SECONDS)
.readTimeout(100, TimeUnit.SECONDS)
.writeTimeout(100, TimeUnit.SECONDS)
.build()
retrofit = Retrofit.Builder()
.client(client)
// .addConverterFactory(NullOnEmptyConverterFactory())
.baseUrl(ApiEndPoints.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync())
.build()
}
return retrofit!!.create(ItchekApi::class.java)
}
}