使用TokenAuthenticator
like @theblang答案是handle的正确方法refresh_token
。
这是我的工具(我使用过Kotlin,Dagger,RX,但是您可以将这种想法用于您的案例)
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
注意
认证者流程
- 示例API
getImage()
返回401错误代码
authenticate
里面的方法TokenAuthenticator
会被解雇
- 同步
noneAuthAPI.refreshToken(...)
调用
- 后
noneAuthAPI.refreshToken(...)
响应- >新的令牌会增加头
getImage()
将使用新的标头自动调用(HttpLogging
不会记录此调用)(intercept
内部AuthInterceptor
不会调用)
如果getImage()
仍然由于错误401而失败,则authenticate
内部方法TokenAuthenticator
将触发AGAIN和AGAIN,然后它将多次抛出有关调用方法的错误java.net.ProtocolException: Too many follow-up requests
。您可以通过计数响应来阻止它。例如,如果你return null
在authenticate
经过3次重试,getImage()
将完成和return response 401
如果getImage()
响应成功=>,我们将正常生成结果(就像您正确调用一样getImage()
)
希望对你有帮助