-
-
Save zakrodionov/40c25a6f2713a93c94c682956d75352d to your computer and use it in GitHub Desktop.
Sample Okhttp3 Authenticator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
SampleAuthenticator (c) by Farhan Khan | |
SampleAuthenticator is licensed under a | |
Creative Commons Attribution 3.0 Unported License. | |
http://creativecommons.org/licenses/by/3.0/ | |
*/ | |
class SampleAuthenticator( | |
lazyOtacRepository: Eval<OtacRepository>, | |
lazyPassCodeRepository: Eval<PassCodeRepository>, | |
lazyCurrentScreenHook: Eval<CurrentScreenHookProvider> | |
) : Authenticator { | |
private val otacRepository: OtacRepository by lazy { lazyOtacRepository.value() } | |
private val passCodeRepository: PassCodeRepository by lazy { lazyPassCodeRepository.value() } | |
private val currentScreenHook: CurrentScreenHook? by lazy { | |
lazyCurrentScreenHook.value().currentScreenHook | |
} | |
override fun authenticate(route: Route?, originalResponse: Response): Request? { | |
if (originalResponse.isUnauthorized()) { | |
if (!isEligibleForRefresh(originalResponse)) { | |
return null | |
} | |
if (isTokenRenewable() && retryCount(originalResponse) < 1) { | |
val authData = renewToken() | |
if (authData != null) { | |
if (canRetryRequest(originalResponse, authData)) { | |
return retryRequest( | |
originalResponse, | |
authData, | |
retryCount(originalResponse) + 1 | |
) | |
} | |
} else { | |
otacRepository.clearData() | |
currentScreenHook?.onUnAuthorizedError() | |
} | |
} else { | |
currentScreenHook?.onUnAuthorizedError() | |
} | |
} | |
return null | |
} | |
private fun Response.isUnauthorized() = this.code() == ErrorResultCode.HTTP_UNAUTHORIZED | |
private fun canRetryRequest(originalResponse: Response, currentAuthData: AuthData?) = | |
originalResponse.request().headers(Authorization.NAME).isNotEmpty() | |
&& originalResponse.request().headers(Authorization.NAME)[0] != currentAuthData?.accessToken | |
private fun isTokenRenewable() = | |
otacRepository.getData()?.canRefresh() ?: false | |
private fun isEligibleForRefresh(originalResponse: Response): Boolean { | |
return originalResponse.request().header("x-no-refresh") != true.toString() | |
} | |
private fun renewToken() = | |
runBlocking { | |
when (val result = | |
otacRepository.refresh(OtacRepository.RefreshInformation(passCodeRepository.getPassCode()))) { | |
is SafeResult.Success -> { | |
result.data | |
} | |
else -> { | |
null | |
} | |
} | |
} | |
private fun retryRequest( | |
originalResponse: Response, | |
currentAuthData: AuthData?, | |
retryCount: Int | |
) = | |
currentAuthData?.let { authData -> | |
originalResponse.request().newBuilder() | |
.removeHeader(Authorization.NAME) | |
.removeHeader(HEADER_RETRY_COUNT) | |
.addHeader(Authorization.NAME, Authorization.getValue(authData.accessToken)) | |
.addHeader(HEADER_RETRY_COUNT, "$retryCount") | |
.build() | |
} | |
private fun retryCount(response: Response?): Int { | |
return response?.request()?.header(HEADER_RETRY_COUNT)?.toInt() ?: 0 | |
} | |
companion object { | |
const val HEADER_RETRY_COUNT = "xInternalRetryCount" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment