본문 바로가기
안드로이드

[안드로이드] Firebase Interceptor - with OkHttp3, Retrofit

by keel_im 2021. 11. 25.
반응형

안녕하세요.

오늘은 Interceptor에 대해서 얘기를 해보려고 합니다.

 

여러분들은 개발을 하면서,

Firebase를 많이 붙여서 사용을 하실 때가 많은 것 같습니다. 저도 Firebase를 자주 

애용하는 편인데요. 인증 서비스는 Firebase 로 하고 비즈니스 로직은 기존 서버에서 진행하는데,

Firebase Authentication 으로 발급받은 액세스 토큰을 가지고 통신을 해야 하는 상황이 생깁니다. 


여기서 제가 주목한 점은, Retrofit Service Interface 를 정의를 하면서 Token을 가지고 헤더를 구성하는 것이 아니라, 

Interceptor라는 개념을 이용하여, 자동으로

Authorization 헤더에 토큰 값을 이용하려고 하는 것을 목적으로 두고 있습니다.

https://en.wikipedia.org/wiki/Interceptor_pattern

 

Interceptor pattern - Wikipedia

Example of an interceptor In the field of software development, an interceptor pattern is a software design pattern that is used when software systems or frameworks want to offer a way to change, or augment, their usual processing cycle. For example, a (si

en.wikipedia.org

* 여기서 Interceptor 는 간단히 말해, 무언가를 실행하기 전에 붙여지는 것들이라고 저는 이해했습니다. 이러한 Interceptor 들은 JavaScript 에서 axios 라이브러리를 사용하여도 동일한 개념을 쓰일 수가 있습니다.


코드를 한번 보겠습니다.

class ApiRequestFactory @Inject constructor(
    
) {
    private val baseUrl = ""
    private val moshi = Moshi.Builder()
        .add(KotlinJsonAdapterFactory())
        .build()

    val retrofit: FreeServices = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(MoshiConverterFactory.create(moshi))
        .client(
            OkHttpClient.Builder()
                .addInterceptor(
                    HttpLoggingInterceptor().apply {
                        this.level = HttpLoggingInterceptor.Level.BODY
                    }
                )
                .addInterceptor(
                    PlutoInterceptor()
                )
                .addInterceptor(AuthInterceptor())
                .build()
        )
        .build()
        .create()

    class AuthInterceptor : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {
            val request = chain.request()
            val result = runCatching {
                val user = FirebaseAuth.getInstance().currentUser ?: return chain.proceed(request)
                val task: Task<GetTokenResult> = user.getIdToken(false)
                val tokenResult: GetTokenResult =
                    Tasks.await(task, 10, java.util.concurrent.TimeUnit.SECONDS) // Timeout 10 Seconds
                tokenResult.token ?: return chain.proceed(request)
            }

            return if(result.isSuccess){
                val token = result.getOrNull()
                chain.proceed(
                    request.newBuilder()
                        .addHeader("Content-Type", "application/json")
                        .addHeader("Authorization", "Bearer $token")
                        .build())
            } else{
                chain.proceed(request) // No has auth header
            }
        }
    }
}

저의 지금 프로젝트 환경은, Firebase 를 인증으로 사용하고 있고, Retrofit + Moshi와 Pluto를 사용하고 있습니다.

저희가 봐야하는 부분은 AuthInterceptor 클래스입니다.

Interceptor 를 만드는 방법은 유사하고, 저는 Firebase-ktx를 사용하여 currentUser 가 null 이 아닌 경우 액세스 토큰을 가져와 Header에 붙이는 방식으로 AuthInterceptor를 구성했습니다.

또한 이 class 를 addInterceptor 하여 추가를 해주었습니다. 

* 여기서 DI 를 사용하여 객체를 주입을 한다면 @Inject constructor 안에 주입을 해주시면 됩니다. 

 


사실 SharedPreference 를 사용해서 토큰을 가져와서 붙이는 것이 더 간단할 수 있습니다. 

여러분 개발 상황에 맞추어 적절히 개발을 하시면 좋을 것 같습니다. 

 

 

반응형

댓글