Sử dụng TokenAuthenticator
câu trả lời như @theblang là một cách chính xác để xử lý refresh_token
.
Đây là cách triển khai của tôi (Tôi đã sử dụng Kotlin, Dagger, RX nhưng bạn có thể sử dụng ý tưởng này để triển khai cho trường hợp của bạn)
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()
}
}
Để ngăn chặn chu kỳ phụ thuộc như bình luận @Brais Gabin, tôi tạo 2 giao diện như
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>
}
và
interface PotoAuthApi { // Authentication API
@GET("api/images")
fun getImage(): Single<GetImageResponse>
}
AccessTokenWrapper
lớp học
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
lớp học
data class AccessToken(
@Expose
var token: String,
@Expose
var refreshToken: String)
Đánh chặn của tôi
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())
}
}
Cuối cùng, thêm Interceptor
và Authenticator
vào OKHttpClient
khi bạn tạo dịch vụ PotoAuthApi
Bản giới thiệu
https://github.com/PhanVanLinh/AndroidMVPKotlin
Ghi chú
Dòng xác thực
- API ví dụ
getImage()
trả về mã lỗi 401
authenticate
phương pháp bên trong TokenAuthenticator
sẽ bị sa thải
- Đồng bộ hóa
noneAuthAPI.refreshToken(...)
được gọi
- Sau khi
noneAuthAPI.refreshToken(...)
phản hồi -> mã thông báo mới sẽ thêm vào tiêu đề
getImage()
sẽ TỰ ĐỘNG được gọi với tiêu đề mới ( HttpLogging
S NOT KHÔNG đăng nhập cuộc gọi này) ( intercept
bên trong AuthInterceptor
SILL KHÔNG GỌI )
Nếu getImage()
vẫn không thành công với lỗi 401, authenticate
phương thức bên trong TokenAuthenticator
sẽ kích hoạt LẠI và LẠI sau đó nó sẽ ném lỗi về phương thức cuộc gọi nhiều lần ( java.net.ProtocolException: Too many follow-up requests
). Bạn có thể ngăn chặn nó bằng cách phản ứng đếm . Ví dụ, nếu bạn return null
ở authenticate
sau 3 lần thử lại, getImage()
sẽ hoàn thành vàreturn response 401
Nếu getImage()
phản hồi thành công => chúng tôi sẽ cho kết quả bình thường (như bạn gọi getImage()
không có lỗi)
Hy vọng nó sẽ giúp