개인적으로는 토큰이 expired되었는데 재발급을 해주는 것은 안전하지 않다는 생각이구요. 토큰이 expired 되기 전에 refresh token 을 보내면 재발급 해주는 것이 안전하다고 생각합니다.
어쨋든, 해당 기능의 구현은 OkHttp에 Authenticator라는게 있는데 이걸 이용하라고 되어 있더라구요. 하지만 여기에는 의견이 갈라지는 듯 합니다. Authenticator가 추가적인 API 호출을 하는 듯합니다. 개인적으로는 안사용하고 있습니다.
인터셉터를 사용해서 이런 식으로 구현이 가능할 것 같습니다. (테스트는 안해봤습니다.)
interface Observervable<T> {
fun registerObserver(observer: T)
fun unregisterObserver(observer: T)
}
abstract class Observervable<T>: Observervable<T> {
protected val observers = hashSetOf<T>()
override fun registerObserver(observer: T) {
observers.add(observer)
}
override fun unregisterObserver(observer: T) {
observers.remove(observer)
}
}
class TokenExpirationObserver {
fun onTokenExpired()
}
class LogInterceptor : Interceptor, BaseObservable<TokenExpirationObserver> {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
var response = chain.proceed(request)
Log.e("tag", "request? " + request.method)
Log.e("tag", "response code? " + response.code)
Log.e("tag", "response url? " + response.request.url)
Log.e("tag", "response header? " + response.request.headers)
if (tokenExpired) notifyTokenExpired()
return response
}
private fun notifyTokenExpired() {
for (observer in observers) {
observer.onTokenExpired()
}
}
}
LoginInterceptor 를 Observer 패턴을 사용해서 Observable 로 만듭니다. 그리고 토큰이 expired 되었을 때 Observer 들에게 알려줍니다. LoginInterceptor는 Singleton 으로 만드신 다음 인스턴스를 공유해서 사용하면 될 것 같습니다.
이걸 사용하는 쪽에서는 observer로 등록하고 이벤트가 오면 처리하면 되겠죠. 전 ViewModel을 예로 들었지만, 다른 클래스들에서도 같은 방법으로 사용할 수 있을 것 같습니다.
class MainViewModel(
private val tokenExpirationObservable: LoginInterceptor
): ViewModel, TokenExpirationObserver {
override fun onTokenExpired() {
requestAccessTokenRenewal()
}
fun onStart() {
tokenExpirationObservable.registerObserver(this)
}
fun onStop() {
tokenExpirationObservable.unregisterObserver(this)
}
}