令牌刷新后再次呼叫Api

时间:2019-07-17 14:32:40

标签: android kotlin retrofit okhttp3

我正在使用 Authenticator (而不是 Interceptor )来刷新令牌。我能够检测到401异常并轻松刷新新令牌。一切运行正常,但问题出在以下地方:

我无法再次调用该请求,我不希望用户再次点击以调用该报价。

因此,执行下面的代码后,我得到了一个新的令牌,它给了我401错误消息。 我的问题是:如何再次调用请求链? 欢迎提供任何有关实施的建议。

OffersViewModel类

    val observable = ApiServiceClient.createApiUsingToken(context).getOffers(
                                Pref.getString(getApplication(), Pref.CUSTOMER_CODE, "")!!,
                                Pref.getString(getApplication(), Pref.TOKEN, "")!!
                        )
                        compositeDisposable.add(observable.subscribeOn(Schedulers.io())
                                .observeOn(AndroidSchedulers.mainThread())
                                .doOnSubscribe {
                                    responseModel.statusCode = StatusCode.START
                                    offersRegisteredUserResponseLiveData.postValue(responseModel)
                                }
                                .subscribe({ success ->
                                    if (success.errors.isNullOrEmpty()) {
                                        success.statusCode = StatusCode.SUCCESS
                                    } else {
                                        success.statusCode = StatusCode.ERROR
                                    }
                                    offersRegisteredUserResponseLiveData.value = success
                                }, {
//HERE I GOT 401
                                    Log.d("debug",it.message.toString())
                                    responseModel.statusCode = StatusCode.ERROR
                                    offersRegisteredUserResponseLiveData.value = responseModel
                                }, { })
                        )

API服务类

/*.....Offer Screen...........*/
    @GET("offers/xyz/{abc}")
    fun getOffers(
            @Path("abc") customerCode: String,
            @Header("Authorization") authorization: String,
            @Header("Content-Type") contentType: String = CONTENT_TYPE
    ):
            Observable<OfferRegisteredUserResponseModel>

ApiClient类

fun createApiUsingToken(context: Context?): ApiService {
            val interceptor = HttpLoggingInterceptor()
            interceptor.level = HttpLoggingInterceptor.Level.BODY
            val client = OkHttpClient.Builder().addInterceptor(interceptor).connectTimeout(20, TimeUnit.SECONDS)
                    .writeTimeout(20, TimeUnit.SECONDS)
                    .readTimeout(60, TimeUnit.SECONDS)
                    .authenticator(TokenInterceptor(context)).build()


            val retrofit = Retrofit.Builder()
                    .client(client)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create())
                    .baseUrl(Constants.BASE_URL)
                    .build()
            var ApiServiceClient=retrofit.create(ApiService::class.java)
            return retrofit.create(ApiService::class.java)
        }

类TokenInterceptor

var requestAvailable: Request? = null
        if (response!!.code() === 401) {
            var retrofitResponse = ApiServiceClient.createToken().getTokenWithoutObserver().execute()
            if (retrofitResponse != null) {
                val refreshTokenResponse = retrofitResponse!!.body()
                val newAccessToken = refreshTokenResponse!!.token
                if (newAccessToken != null)
                {
                    Pref.setString(MyApplication.mInstance, Pref.TOKEN, "${refreshTokenResponse.tokenType} ${refreshTokenResponse?.token}")
                    Pref.setString(MyApplication.mInstance, Pref.TOKEN_EXPIRES_IN, refreshTokenResponse.tokenExpirationTime.toString())
                    Utils.addTokenExpirationTimeToCurrentTime(MyApplication.mInstance, refreshTokenResponse.tokenExpirationTime?.toInt()!!)

                    try {
                        requestAvailable = response?.request()?.newBuilder()
                                ?.addHeader("Content-Type", "application/json")
                                ?.addHeader("Authorization", "Bearer " + newAccessToken)
                                ?.build()
                        return requestAvailable
                    } catch (ex: Exception) {
                    }
            }
            } else
                return null
        }
        return requestAvailable

1 个答案:

答案 0 :(得分:0)

我认为事情错了。

首先是,即使您使用新令牌“重新启动”请求,如果恰好在未保存“新令牌”的情况下再次发出请求,该请求也将失败。

第二个是我看不到您将新令牌保存在任何地方(例如,在SharedPrefs中供以后使用)。

这就是我要做的:(preferenceHelper是SharedPrefs)

override fun authenticate(route: Route?, response: Response): Request? {
    val HEADER_AUTHORIZATION = "Authorization"
    // We need to have a token in order to refresh it.
    val token = preferenceHelper.getAccessToken() ?: return null

    synchronized(this) {
        val newToken = preferenceHelper.getAccessToken() ?: return null

        // Check if the request made was previously made as an authenticated request.
        if (response.request().header(HEADER_AUTHORIZATION) != null) {

            // If the token has changed since the request was made, use the new token.
            if (newToken != token) {
                return response.request()
                    .newBuilder()
                    .removeHeader(HEADER_AUTHORIZATION)
                    .addHeader(HEADER_AUTHORIZATION, "Bearer " + newToken)
                    .build()
            }
            val tokenResponse = ApiServiceClient.createToken().getTokenWithoutObserver().execute()

            if (tokenResponse.isSuccessful) {

                val userToken = tokenResponse.body() ?: return null

                preferenceHelper.saveAccessToken(userToken.token)
                preferenceHelper.saveRefreshToken(userToken.refreshToken)

                // Retry the request with the new token.
                return response.request()
                    .newBuilder()
                    .removeHeader(HEADER_AUTHORIZATION)
                    .addHeader(HEADER_AUTHORIZATION, "Bearer " + userToken.token)
                    .build()
            } else {
                logoutUser()
            }
        }
    }
    return null
}