안녕하세요.
오늘은 Interceptor에 대해서 얘기를 해보려고 합니다.
여러분들은 개발을 하면서,
Firebase를 많이 붙여서 사용을 하실 때가 많은 것 같습니다. 저도 Firebase를 자주
애용하는 편인데요. 인증 서비스는 Firebase 로 하고 비즈니스 로직은 기존 서버에서 진행하는데,
Firebase Authentication 으로 발급받은 액세스 토큰을 가지고 통신을 해야 하는 상황이 생깁니다.
여기서 제가 주목한 점은, Retrofit Service Interface 를 정의를 하면서 Token을 가지고 헤더를 구성하는 것이 아니라,
Interceptor라는 개념을 이용하여, 자동으로
Authorization 헤더에 토큰 값을 이용하려고 하는 것을 목적으로 두고 있습니다.
https://en.wikipedia.org/wiki/Interceptor_pattern
* 여기서 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 를 사용해서 토큰을 가져와서 붙이는 것이 더 간단할 수 있습니다.
여러분 개발 상황에 맞추어 적절히 개발을 하시면 좋을 것 같습니다.
'안드로이드' 카테고리의 다른 글
[안드로이드] 힐트(Hilt)를 사용하면서 - @Binds (4) | 2021.12.19 |
---|---|
[안드로이드] SDK 31 대응 사항 중 PendingIntent 에 관하여 (0) | 2021.12.07 |
[안드로이드] 컴포즈로 조금씩 바꿔보자. (with Progress bar) (0) | 2021.09.29 |
[안드로이드] Gradle Type-safe project accessors (2) | 2021.09.23 |
[안드로이드] ksp (kotlin symbol processing) 적용기 (0) | 2021.09.08 |
댓글