ใช้TokenAuthenticator
เหมือนคำตอบ @theblang 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)
Interceptor ของฉัน
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
จะเริ่มต้นอีกครั้งและอีกครั้งแล้วมันจะโยนข้อผิดพลาดเกี่ยวกับวิธีการโทรหลายครั้ง ( java.net.ProtocolException: Too many follow-up requests
) คุณสามารถป้องกันได้โดยการตอบสนองนับ ตัวอย่างเช่นถ้าคุณreturn null
อยู่ในauthenticate
หลัง 3 ครั้งลองใหม่getImage()
จะเสร็จสิ้นและreturn response 401
หากการgetImage()
ตอบสนองสำเร็จ => เราจะส่งผลให้ตามปกติ (เช่นคุณโทรgetImage()
โดยไม่มีข้อผิดพลาด)
หวังว่ามันจะช่วย