본문으로 바로가기

RestApi는 Http 요청을 보낼 인터페이스 정의

public interface RestApi {
@FormUrlEncoded
@POST("/auth/token")
Call<Map<String, String>> getToken(@Field("phone") String phone, @Field("email") String email, @Field("password") String password);
@FormUrlEncoded
@PATCH("/auth/token")
Call<Map<String, String>> refreshToken(@Field("refresh_token") String refreshToken); }

Retrofit 클래스로 RestApi 인터페이스를 구현하여 이용하여 서버와 통신

Retrofit retrofit = new Retrofit.Builder()
.baseUrl(getUrl())
.addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()))
.build();
RestApi api = retrofit.create(restApi.class);

하지만, 토큰 인증 방식으로 구현하기 위해서는 Http 요청과정에서 지속적으로 token을 헤더에 추가하여 요청을 해야하는 문제가 발생한다.

@FormUrlEncoded
@POST("/auth/token")
Call<Map<String, String>> getToken(@Header("Authorization") String token, @Field("phone") String phone, @Field("email") String email, @Field("password") String password);

위 방법 처럼 동적인 헤더는 @Header 어노테이션을 이용하여 추가할 수 있지만 Http 요청을 추가 할때마다 지속적으로 매개변수를 추가해주어야 하는 문제가 발생한다.

모든 Http요청에 헤더를 추가하기 위해서는 OkHttp interceptor를 이용해야 한다.

RetrofitBuilder retrofitBuilder = new Retrofit.Builder()
.baseUrl(getUrl())
.addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()));

Interceptor interceptor = new Interceptor() {
@Override
public okhttp3.Response intercept(@NonNull Chain chain) throws IOException {
String token = User.getInstance().getAccessToken();
Request newRequest;
if (token != null && !token.equals("")) { // 토큰이 없는 경우
// Authorization 헤더에 토큰 추가
newRequest = chain.request().newBuilder().addHeader("Authorization", token).build();
Date expireDate = user.getExpireDatetime();
if (expireDate.getTime() <= System.currentTimeMillis()) { // 토큰 만료 여부 체크
user.setAccessToken(null);
// refreshToken 토큰 갱신 api 호출
Map<String, String> body = api.refreshToken(user.getRefreshToken()).execute().body();

if (body != null) {
// 클라이언트의 토큰 갱신 수행하여 tokenStr 변수에 삽입

newRequest = chain.request().newBuilder().addHeader("Authorization", tokenStr).build();
return chain.proceed(newRequest);
}
}
} else newRequest = chain.request();
return chain.proceed(newRequest);
}
};

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(interceptor);
OkHttpClient client = builder.build();
retrofitBuilder.client(client);

Retrofit retrofit = retrofitBuilder.build();
RestApi api = retrofit.create(restApi.class);

intercept메서드 영역은 Http 요청전에 이루어지는 로직이여서 클라이언트에 토큰이 있다면 헤더에 토큰을 추가하여 요청한다.

만약 토큰이 만료되었다면 토큰을 갱신하는 api인 api.refreshToken 메서드를 실행하고 요청 받은 결과로 얻은 토큰을 클라이언트에 갱신한다.



참고자료: https://academy.realm.io/kr/posts/droidcon-jake-wharton-simple-http-retrofit-2/

https://futurestud.io/tutorials/retrofit-add-custom-request-header

https://stackoverflow.com/questions/41514375/retrofit-add-header-with-token-and-id

https://github.com/square/okhttp/wiki/Interceptors