retrofit으로 api 호출 중 세션 종료나 토큰 만료 시 특정 화면으로 이동하거나 토큰 갱신을 해야할 때 사용한다.
세션 종료 시 로그인 화면으로 이동하기
// 세션 종료 시 로그인 화면으로 이동하기 class SessionAuthenticator : Authenticator { override fun authenticate(route: Route?, response: Response): Request? { if (response.code == HttpURLConnection.HTTP_UNAUTHORIZED && !SessionExpiredManager.isExpired && App.instance.currentActivity !is SignInActivity ) { SessionExpiredManager.isExpired = true Intent(App.instance, SignInActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK putExtra(SignInActivity.SHOW_SESSION_EXPIRED_MESSAGE, true) }.also { App.instance.startActivity(it) } } return null } }
if 에 조건이 많은 건, 동시에 여러 api의 호출결과를 받아도 로그인 화면은 한 번만 호출을 하기위해서다. App.kt
클래스는 http://susemi99.kr/5149 에 있고, SessionExpiredManager.isExpired
는 object 클래스에 변수만 하나 딸랑 있는거다.
토큰 만료 시 갱신하기
class TokenAuthenticator : Authenticator { override fun authenticate(route: Route?, response: Response): Request? { if (response.code == HttpURLConnection.HTTP_UNAUTHORIZED) { if (AppPreference.refreshToken.isNotEmpty()) { val refreshTokenResponse = RefreshTokenService.refresh(AppPreference.refreshToken).execute() if (handleResponse(refreshTokenResponse)) return makeRequest(response) } } return null } private fun handleResponse(refreshTokenResponse: retrofit2.Response<Token>): Boolean { return if (refreshTokenResponse.isSuccessful && refreshTokenResponse.body() != null) { AppPreference.saveToken(refreshTokenResponse.body()!!) true } else { UserRepository.instance.logout() false } } private fun makeRequest(response: Response): Request { return response.request .newBuilder() .removeHeader("Authorization") .addHeader("Authorization", AppPreference.accessToken) .build() } }
dispose()
를 할 수 없으니 다른 api는 RxJava를 사용하더라도 RefreshTokenService.refresh()
는 retrofit의 기본인 Call<Any>
을 사용하는게 좋다.