TokenAuthenticatorLike @theblang yanıtı kullanmak işlemek için doğru bir yoldur refresh_token.
İşte benim alet (Kotlin, Dagger, RX kullanıyorum ama bu fikri davanıza uygulamak için kullanabilirsiniz)
TokenAuthenticator
class TokenAuthenticator @Inject constructor(private val noneAuthAPI: PotoNoneAuthApi, private val accessTokenWrapper: AccessTokenWrapper) : Authenticator {
override fun authenticate(route: Route, response: Response): Request? {
val newAccessToken = noneAuthAPI.refreshToken(accessTokenWrapper.getAccessToken()!!.refreshToken).blockingGet()
accessTokenWrapper.saveAccessToken(newAccessToken) // save new access_token for next called
return response.request().newBuilder()
.header("Authorization", newAccessToken.token) // just only need to override "Authorization" header, don't need to override all header since this new request is create base on old request
.build()
}
}
Öneleyen için bağımlılık döngüsü @Brais Gabin açıklama gibi, ben oluşturmak 2 arayüzü gibi
interface PotoNoneAuthApi { // NONE authentication API
@POST("/login")
fun login(@Body request: LoginRequest): Single<AccessToken>
@POST("refresh_token")
@FormUrlEncoded
fun refreshToken(@Field("refresh_token") refreshToken: String): Single<AccessToken>
}
ve
interface PotoAuthApi { // Authentication API
@GET("api/images")
fun getImage(): Single<GetImageResponse>
}
AccessTokenWrapper sınıf
class AccessTokenWrapper constructor(private val sharedPrefApi: SharedPrefApi) {
private var accessToken: AccessToken? = null
// get accessToken from cache or from SharePreference
fun getAccessToken(): AccessToken? {
if (accessToken == null) {
accessToken = sharedPrefApi.getObject(SharedPrefApi.ACCESS_TOKEN, AccessToken::class.java)
}
return accessToken
}
// save accessToken to SharePreference
fun saveAccessToken(accessToken: AccessToken) {
this.accessToken = accessToken
sharedPrefApi.putObject(SharedPrefApi.ACCESS_TOKEN, accessToken)
}
}
AccessToken sınıf
data class AccessToken(
@Expose
var token: String,
@Expose
var refreshToken: String)
Önleme Sahibim
class AuthInterceptor @Inject constructor(private val accessTokenWrapper: AccessTokenWrapper): Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val authorisedRequestBuilder = originalRequest.newBuilder()
.addHeader("Authorization", accessTokenWrapper.getAccessToken()!!.token)
.header("Accept", "application/json")
return chain.proceed(authorisedRequestBuilder.build())
}
}
Son olarak, eklemek Interceptorve Authenticatorsizin için OKHttpClientoluşturabilir servis PotoAuthApi
gösteri
https://github.com/PhanVanLinh/AndroidMVPKotlin
Not
Kimlik doğrulayıcı akışı
- Örnek API
getImage()dönüşü 401 hata kodu
authenticateyöntem içeride TokenAuthenticatorolacak ateş
- Senkronize
noneAuthAPI.refreshToken(...)denilen
- Yanıttan sonra
noneAuthAPI.refreshToken(...)-> yeni simge başlığa eklenecek
getImage()irade OTO denilen (yeni bir başlıkla HttpLogging giriş OLMAYACAKTIR (bu çağrıyı) interceptiçindeki AuthInterceptor WILL DİYE DEĞİL )
Eğer getImage()hala hata 401 ile başarısız oldu, authenticateiçeride yöntem TokenAuthenticatorirade TEKRAR ateş ve TEKRAR (o zaman çağrı yöntemi birçok zaman hakkında hata atmak olacaktır java.net.ProtocolException: Too many follow-up requests). Cevabı sayarak önleyebilirsiniz . Örnek, eğer return nulliçinde authenticate3 kez yeniden deneme sonrasında, getImage()olacak bitirmek vereturn response 401
Eğer getImage()(aramak gibi tepki başarı => normalde sonucu sonuçlanacaktır getImage()hiçbir hata ile)
Umarım yardımcı olur