TokenAuthenticator@Theblang उत्तर की तरह उपयोग करना संभाल के लिए एक सही तरीका है refresh_token।
यहाँ मेरा कार्यान्वयन है (मुझे कोटलिन, डैगर, आरएक्स का उपयोग करना है लेकिन आप इस विचार का उपयोग अपने मामले पर लागू करने के लिए कर सकते हैं)
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()
}
}
@Brais Gabin टिप्पणी जैसे निर्भरता चक्र को रोकने के लिए , मैं 2 इंटरफ़ेस बनाता हूं जैसे
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>
}
तथा
interface PotoAuthApi { // Authentication API
@GET("api/images")
fun getImage(): Single<GetImageResponse>
}
AccessTokenWrapper कक्षा
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 कक्षा
data class AccessToken(
@Expose
var token: String,
@Expose
var refreshToken: String)
मेरा इंटरसेप्टर
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())
}
}
अंत में, जोड़ने Interceptorऔर Authenticatorअपने को OKHttpClientजब बनाने सेवा PotoAuthApi
डेमो
https://github.com/PhanVanLinh/AndroidMVPKotlin
ध्यान दें
प्रामाणिक प्रवाह
- उदाहरण एपीआई
getImage()वापसी 401 त्रुटि कोड
authenticateअंदर की विधि निकाल दीTokenAuthenticator जाएगी
- संक्रान्ति
noneAuthAPI.refreshToken(...)कहा जाता है
noneAuthAPI.refreshToken(...)प्रतिक्रिया के बाद -> नया टोकन हेडर में जोड़ देगा
getImage()क्या ऑटो को नए हेडर के साथ बुलाया जाएगा ( इस कॉल को HttpLogging लॉग इन नहीं किया जाएगा ) ( interceptअंदर कॉल AuthInterceptor नहीं होगी )
यदि getImage()अभी भी त्रुटि 401 के साथ विफल हो गई है, तो authenticateअंदर की विधि AGAIN और AGAINTokenAuthenticator को निकाल देगी तो यह कई बार कॉल विधि के बारे में त्रुटि फेंक देगा ( java.net.ProtocolException: Too many follow-up requests)। आप इसे प्रतिसाद प्रतिक्रिया से रोक सकते हैं । उदाहरण के लिए, यदि आप return nullमें authenticateके बाद 3 बार पुन: प्रयास, getImage()होगा खत्म औरreturn response 401
यदि getImage()प्रतिक्रिया सफलता => हम सामान्य रूप से परिणाम प्राप्त करेंगे (जैसे आप getImage()बिना किसी त्रुटि के कॉल करते हैं)
आशा है कि यह मदद करेगा