-
Notifications
You must be signed in to change notification settings - Fork 0
토큰 만료 시 재인증 하는 방법
Sieun Ju edited this page Feb 12, 2022
·
8 revisions
- OkHttp 제공하는 Authenticator 인터페이스를 사용하여 토큰 만료시 자동으로 재 인증처리를 구현합니다.
- 사용자가 JWT 토큰을 사용하면 만료되는 시간이 있습니다. 그 안에 앱을 접속 하면 서버에서 RefreshToken을 발급 받아 사용하게 되지만, 이후에 접속하면 토큰이 만료되는 코드인 ‘401’ 코드를 뱉게 됩니다.
- 토큰 만료시 보통 로그인 페이지로 이동처리하게 되는데 이러한 과정은 사용자에게 좋지 않는 결과를 뱉게 됩니다.
- OkHttp 에서 제공하는 Authenticator Interface 를 사용하여 토큰 재인증 처리를 구현합니다.
- authenticate 함수안에 매개변수인 Response 에서 상태 코드값을 가져와서 재인증 처리를 구현합니다.
- Authenticator 클래스를 생성할때 생성자로 재인증 하는 API Service 를 매개변수로 가져옵니다. 필요에 따라서 토큰을 발급을 받으면 저장하고 관리할수 있는 LoginManager 도 추가로 가져옵니다.
- Rx 에서 지원하는 blockingGet 함수를 통해 API 통신을 동기적으로 처리해서 토큰을 가져오도록 처리합니다.
com.til.data.interceptor.TokenAuthenticator.kt
override fun authenticate(route: Route?, response: Response): Request? {
// Token Expired JWT 토큰 만료시 코드 => 401
return if (response.code == 401) {
val tokenResponse = apiService.tokenRefresh().blockingGet()
// Token 저장
loginManager.setToken(tokenResponse.data?.token ?: "")
response.request.newBuilder().apply {
header(NetworkConfig.HEADER_KEY_ACCEPT, NetworkConfig.HEADER_VAL_ACCEPT)
header(NetworkConfig.HEADER_KEY_CONTENT, NetworkConfig.HEADER_VAL_CONTENT)
header(NetworkConfig.HEADER_KEY_TOKEN, loginManager.getToken())
}.build()
} else {
null
}
}
-
테스트 진행 방식
- 만료된 토큰을 발급 받은 후 아무 API 요청했을때 정상적으로 받아 오는지 테스트합니다.
- 테스트 서버가 만료된 토큰 판단하는 기준은 Header 에서 ‘token’ 값중에 ‘Expired’ 라는 값이 있으면 ‘401’ 코드를 리턴하도록 처리 했습니다.
-
만료된 토큰을 헤더에 셋팅하고 (https://til.qtzz.synology.me/api/test) API 요청합니다.
--> GET <https://til.qtzz.synology.me/api/test> accept: application/json Content-Type: application/json token: Token Expired 1642164973740 --> END GET HTTP CODE (401) // 토큰 재인증 API 요청 --> POST <https://til.qtzz.synology.me/api/auth/refresh> Content-Length: 0 accept: application/json Content-Type: application/json --> END POST (0-byte body) <-- 200 <https://til.qtzz.synology.me/api/auth/refresh> (112ms) content-type: application/json; charset=utf-8 content-length: 58 {"status":true,"data":{"token":"Token Migane Koda Dewdy"}} <-- END HTTP (58-byte body) // 토큰을 새로 발급 받은후 에러로 리턴받은 API를 재 호출합니다. <-- 200 <https://til.qtzz.synology.me/api/test> (229ms) content-type: application/json; charset=utf-8 content-length: 215 {"status":true,"data":{"integer":1642164978292,"str":"TIL Message"}}
-
추가로 성능 테스트를 해봤습니다.
- 실제로 서비스 할때에는 앱 처음 진입시 토큰이 만료 된경우 토큰을 새로 받아 처리해서 앱 실행 중간에 토큰이 만료되는 경우는 없지만, 모든 변수는 생각해야 하기때문에 멀티 쓰레드 환경에서 중간에 토큰이 만료 됐을때 오류 없이 Response 을 받는지 테스트 해봤습니다.
- 결과부터 말씀 드리자면 성공적으로 HTTP 통신이 이루어졌습니다. 다만, 멀티 쓰레드 환경에서 중간에 토큰이 만료되기때문에 ‘리프레시 토큰 API’ 를 여러번 호출하고 토큰에 대한 값이 변경이 되었지만 이건 그렇게 심각한 문제가 되어 보이진 않았습니다. (서버쪽에 이슈가 생길지도...?)
- 멀티 쓰레드 환경에서 중간에 토큰을 만료 시켰을때 다른 HTTP 통신이 어떻게 이루어지는지 테스트 해봤습니다.
- 코드 예시
private fun multiApiInterval() {
Flowable.interval(0, 100, TimeUnit.MILLISECONDS)
.doOnSubscribe {
if (Random.nextBoolean()) {
expiredToken()
}
}
.onBackpressureBuffer()
.take(10)
.flatMap { multiApi() }
.doOnComplete {
JLogger.d("MultiApi SUCCESS")
}
.subscribe({
}, {
JLogger.e("ERROR $it")
}).addTo(compositeDisposable)
}
private fun multiApi(): Flowable<Any> {
return Single.merge(
getJSendUseCase(),
getJSendWithMetaUseCase(),
getJSendListUseCase(),
getJSendListWithMetaUseCase()
)
}