Обработка истечения срока действия маркера доступа при нестабильной работе интернета - PullRequest
0 голосов
/ 14 декабря 2018

Я использую Retrofit2 в качестве HTTP-клиента для Android.Приложение использует токен доступа и токен обновления для связи с серверной частью.

Сценарий 1. Истек срок доступа к токену, вызов API завершается неудачно с кодом ошибки 401, после чего я использую Authenticator для использования токена обновления для получения новой пары токенов доступа и токенов обновления ипродолжить с новым токеном доступа для неудавшегося вызова.Все это хорошо работает при стабильном подключении к Интернету

Сценарий 2: Теперь учтите, что Интернет не стабилен и продолжает падать и выключаться.Интернет есть, вызов API прерывается из-за истекшего токена доступа, приложение выполняет входящий вызов с обновлением токена, чтобы получить новую пару токена доступа и обновления токена.Но прежде, чем я получу успех 200 для входа в систему, интернет звонит.Теперь Интернет вернулся, и мое приложение снова запускает вызов API и получает 401, а затем использует токен обновления для запуска нового входа в систему.Проблема в том, что сервер обновил новые маркеры доступа и обновления, но приложение так и не получило его, когда интернет отключился.Из-за этого токен обновления, который у меня был, больше не действителен (так как новая пара уже создана в бэкэнде и очищена от старого)

Не знаете, как мне поступить с этим сценарием?Вот мой класс аутентификатора:

public class MyAuthenticator implements Authenticator {

Context context;

public MyAuthenticator(Context context) {
    this.context = context;
}

@Nullable
@Override
public Request authenticate(Route route, Response response) throws IOException {

    Retrofit client = new Retrofit.Builder()
            .baseUrl(Manager.API_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    ApiService service = client.create(ApiService.class);

    SharedPreferenceManager sharedPreferenceManager = new SharedPreferenceManager(context);
    String refreshToken = sharedPreferenceManager.getRefreshToken(context);

    AuthRequest authRequest = new AuthRequest();
    authRequest.grant_type = "refresh_token";
    authRequest.refresh_token = refreshToken;

    Call<authResponse> refreshTokenResult = service.refreshToken(authRequest);
    retrofit2.Response accessTokenResponse = refreshTokenResult.execute();
    //check if response equals 400 , mean empty response
    if (accessTokenResponse.isSuccessful()) {
        AuthResponse refreshResult  = (AuthResponse) accessTokenResponse.body();
        //save new access and refresh token
        sharedPreferenceManager.writeLoginResponse(context, refreshResult);
        // then create a new request and modify it accordingly using the new token
        return response.request().newBuilder()
                .header("Authorization", "Bearer " + refreshResult.access_token)
                .build();

    } else {
        LoginActivity_.intent(context).flags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK).start();
        return null;

    }
}

}

Не уверен, что мне не хватает и как мне решить эту проблему.

1 Ответ

0 голосов
/ 15 декабря 2018

Вы не можете ничего с этим поделать на стороне клиента.

То, что вы пытаетесь сделать, - это точная однократная доставка новых токенов, , что невозможно .Вместо этого вам следует спроектировать доставку как минимум один раз.

Необходимо подготовить сервер к этому сценарию, то есть он должен также принять старый токен обновления, пока не получит новый токен доступа ИЛИ токен обновления вхотя бы один раз.

До этого сервер не может быть уверен, что клиент получил новые токены.

...