Когда обменивать токен доступа с токеном обновления - PullRequest
0 голосов
/ 15 января 2019

Я понимаю, что поток для использования OAuth2:

после истечения срока действия недействительного токена доступа (сервер возвращает 401), клиент должен запросить новый, используя токен обновления.

Чтобы реализовать его в приложении для iOS (с AFNetworking) или Android (с Volley), я полагаю, что сетевой менеджер должен быть в состоянии обнаружить возвращенную ошибку 401 и затем отправить запрос серверу авторизации.

Проблема связана с одновременным использованием сети. Рассмотрим сценарий, когда доступ истек, приложение отправляет 2 запроса: req1 и через 100 мс req2. Нарисовано на временной шкале, это выглядит так:

req1 --> 401 --> (refresh req) --> OK, new access and fresh tokens --> retry req1
  req2 --> 401 --> (refresh req) --> 403, wrong refresh token

Окончательный результат - req2 завершится ошибкой, и приложение выйдет из системы из-за ошибки 403.

Так что мои вопросы

Эта реализация движется в правильном направлении? Или неправильно получать после получения 401? Должен ли я вместо этого обновить токен, когда пользователь запускает приложение (за счет замедления запуска приложения)

Как я могу решить проблему параллелизма?

1 Ответ

0 голосов
/ 15 января 2019

Поскольку у вас есть менеджер токенов, я бы добавил в него дополнительную логику (на Java):

class TokenManager {

  private String accessToken;
  private CompletableFuture<String> accessTokenRefreshComletableFuture;

  public CompletableFuture<String> getAccessToken() {
    if (this.accessToken is expired) {
       // If refreshed accessToken is being requested
       CompletableFuture<String> runningRequestFuture = this.accessTokenRefreshComletableFuture;
       if (runningRequestFuture == null) {
          // For thread safety, this assignment should be synchronized (or made atomic)
          // with the previous reading
          this.accessTokenRefreshComletableFuture = new CompletableFuture<>();
          // Request a fresh access token.
          // When you get a new access token, set the this.accessTokenRefreshComletableFuture 
          // complete and remove its reference from the manager class.
       }
       return runningRequestFuture;
    }
    // Synchronous result
    return CompletableFuture.completedFuture(this.accessToken);
  }
}

Менеджер не возвращает токен доступа, но CompletableFuture (Promise в JavaScript - асинхронный результат). Если необходимо обновить токен доступа, сначала проверьте, выполняется ли уже запрос конечной точки /token. Если это так, верните это CompletableFuture.

Таким образом, у вас всегда будет либо действительный токен доступа, либо один CompletableFuture, ожидающий новый токен доступа.

...