blog.bouzuya.net

2019-08-29 Retrofit + OkHttp で Authorization ヘッダーを設定する

Retrofit で一部のメソッドだけに Authorization ヘッダーとトークンをつけるには……。以下のソースコードは Kotlin でコンパイルも通していない雰囲気だけのもの。

バージョンは↓。

  • Retrofit 2.6.x
  • OkHttp 4.0.x

↓にある方法のひとつを紹介する。

https://stackoverflow.com/questions/41078866/retrofit-authorization-bearer-token

まず単純な方法はメソッドの引数に @Headder("Authorization") token という引数を追加すること。

interface RetrofitService {
  @GET("users")
  suspend fun getUserList(@Header("Authorization") token: String): List<User>
}

Bearer をつけたければ OkHttp の Interceptor で header を書き換える。

val httpClient = OkHttpClient.Builder().addInterceptor(object : Interceptor {
  override fun intercept(chain: Interceptor.Chain): Response {
    val request = chain.request()
    var newRequest = request.headers["Authorization"]?.let { token ->
      request.newBuilder().header("Authorization", "Bearer $token").build()
    } ?: request
    return chain.proceed(newRequest)
  }
}).build()
// httpClient を Retrofit の client に設定する
// ...

これで動くのだけど認証の必要なメソッド (例ではgetUserList) が token を取るのも何だかなあと。 token はわざわざ引数で取らなくても良いこともあるので……。

そこである種のマーカーとして Retrofit の @Headers を使う。

interface RetrofitService {
  @GET("/users")
  @Headers(AuthorizationInterceptor.placeholder)
  suspend fun getUserList(): List<User>
}

あとはだいたい同じで OkHttp の Interceptor で書き換える。

class AuthorizationInterceptor: Interceptor {
  companion oboject {
    val headerName = "Authorization"
    val headerValue = "DUMMY"
    val placeholder = "$headerName: $headerValue"
  }

  override fun intercept(chain: Interceptor.Chain): Response {
    // token はどこかから得る
    // 例えばコンストラクタに context をとって SharedPreferences から……とか
    val token = // ...
    val request = chain.request()
    var newRequest =
      if (request.header(headerName) == headerValue)
        request.newBuilder().header("Authorization", "Bearer $token").build()
      else
        request
    return chain.proceed(newRequest)
  }
}

// ...

val httpClient =
  OkHttpClient.Builder().addInterceptor(AuthorizationInterceptor()).build()
// httpClient を Retrofit の client に設定する
// ...

どうするのが良いのかは知らないけど一応こんな感じで動く。