web-dev-qa-db-ja.com

Android Retrofit 2.0 Refresh Tokens

私は使っている Retrofit 2.0 Rest APIとの通信用のJacksonコンバーター付き。一部のリクエストでは、承認時にトークンが必要です。持っているトークンが古い場合、別のリクエストでトークンを更新し、そのために失敗した最後のリクエストを繰り返す必要があります。

私の質問:毎回手動で行う必要がありますか、それを自動化する方法はありますか?

現時点での実装方法は次のとおりです。

TrackerService

public interface TrackerService {

    @POST("auth/sendPassword")
    Call<ResponseMessage> sendPassword(@Header("app-type") String appType, 
                                       @Body User userMobile);

    @FormUrlEncoded
    @POST("oauth/token")
    Call<TokenResponse> oathToken(@Field("client_id") String clientId,
                                  @Field("client_secret") String clientSecret,
                                  @Field("grant_type") String grantType,
                                  @Field("username") String username,
                                  @Field("password") String password);

    @FormUrlEncoded
    @POST("oauth/token")
    Call<TokenResponse> refreshToken(@Field("client_id") String clientId,
                                     @Field("client_secret") String clientSecret,
                                     @Field("grant_type") String grantType,
                                     @Field("refresh_token") String username);


    @PUT("me/profile")
    Call<Profile> updateProfile(@Header("app-type") String appType,
                                @Header("Authorization") String token,
                                @Body Profile profile);

}

ServiceGateway

public class ServiceGateway {

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    private static Retrofit retrofit;

    public static <S> S createService(Class<S> serviceClass) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(20 * 1000, TimeUnit.MILLISECONDS)
                .writeTimeout(20 * 1000, TimeUnit.MILLISECONDS)
                .readTimeout(20 * 1000, TimeUnit.MILLISECONDS)
                .addInterceptor(interceptor).build();

        Retrofit.Builder builder =
                new Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .addConverterFactory(JacksonConverterFactory.create());

        retrofit = builder.client(httpClient.build())
                .client(client)
                .build();
        return retrofit.create(serviceClass);
    }

    public static Retrofit getRetrofit() {
        return retrofit;
    }
}

トークンが古くなったときに関数を呼び出して処理する方法

 trackerService = ServiceGateway.createService(TrackerService.class);

    Call<Profile> call = trackerService.updateProfile(getString(R.string.app_type), "Bearer " + userPrefs.accessToken().get(),
            new Profile(trimedInvitationMessage, title,
            String.valueOf(selectedCountry.getCountryCode()), mobilePhone, countryISO, fullName));

    call.enqueue(new Callback<Profile>() {
        @Override
        public void onResponse(Call<Profile> call, Response<Profile> response) {
            if (response.body() != null) {


            } else {
                if (response.raw().code() == 401) {
                    Call<TokenResponse> refreshTokenCall = trackerService.refreshToken(userPrefs.clientId().get(),
            userPrefs.clientSecret().get(), "refresh_token", userPrefs.refreshToken().get());
                    refreshTokenCall.enqueue(new Callback<TokenResponse>() {
                        @Override
                        public void onResponse(Call<TokenResponse> call, Response<TokenResponse> response) {
                            if (response.body() != null) {

                                updateAdviserProfile(trimedInvitationMessage, title, mobilePhone, countryISO, fullName);
                            } else {
                                userPrefs.clear();
                                Intent intent = new Intent(WelcomeActivity_.launcher(EditProfileActivity.this));
                                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                                intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                startActivity(intent);
                                startActivity(WelcomeActivity_.launcher(EditProfileActivity.this));
                            }
                        }

                        @Override
                        public void onFailure(Call<TokenResponse> call, Throwable t) {

                        }
                    });
                } else if (response.raw().code() == 422)
            }
        }

        @Override
        public void onFailure(Call<Profile> call, Throwable t) {
        }
    });
19
vasile

2〜3か月前からこのトピックを検索し、OkHttp 's Authenticatorを見つけました。使用できます。ここに1つのリンクがあります: refreshing-oauth-token-using-retrofit-without-modifying-all-calls

次のように機能します。リクエストが401を返す場合、Authenticatorが移動し、トークンを更新します。ただし、return nullを忘れないでください。または、制限を設定してください。制限しない場合、更新要求が失敗すると複数回更新が試行され、トークンを更新すると同期要求が作成されます。

また、Oauth2トークンの更新に関する質問と回答(両方とも、これらのリンクを検索して自分で作成したもの)があります。

質問: Android-retrofit2-refresh-oauth-2-token

回答: Android-retrofit2-refresh-oauth-2-token-answer

さらに:たとえば、トークンがあり、3時間ごとに更新する必要がある場合。 Interceptorも記述できます。 Interceptor:時間を比較し、401応答を取得せずにトークンを更新します。

Interceptorページを読むことができます: OkHttp Interceptors

こちらもご覧ください: OkHttp handling-authentication

ここにはコードがないことを知っていますが、リンクを試して質問を編集してください。

34
Yasin Kaçmaz