Мне часто приходилось справляться с токенами сессий/доступа, истекающими в дизайне приложений iOS, и никогда не находили на самом деле совершенно определенного дизайна, на котором я на 100% удобен, поэтому я прошу об этом здесь, чтобы узнать, может ли кто-нибудь придумать лучший дизайн, чем я сейчас использую.
Проблема
У вас есть приложение, которое регистрируется с именем пользователя и паролем. Сервер возвращает токен доступа, который должен использоваться для будущих запросов для аутентификации этого пользователя. В какой-то момент в будущем (неизвестное время) сервер истечет с этим токеном, и любой запрос, отправленный с этим токеном, вернет ошибку аутентификации.
После сбоя из-за истечения срока действия сеанса приложение должно повторно войти в систему, используя оригинальные учетные данные, и вернуть новый токен доступа. Затем он может повторить исходный запрос.
Пример
Итак, представьте, что у вас есть API, чтобы получить список новостей, требующих проверки подлинности. Поток может выглядеть следующим образом:
- Пользователь регистрируется и приложение получает токен.
- Просмотр контроллера обновляет список новостей.
- Запрос API выполняется с прикрепленным токеном.
- Запрос API успешно и просмотр обновляется новыми статьями.
- Приложение закрыто и проходит некоторое время.
- Приложение открывается, и в этот момент контроллер просмотра хочет обновить список новостей.
- Запрос API выполняется с прикрепленным токеном.
- Запрос API не увенчался успехом, так как токен истек.
- Контроллер просмотра обновляет токен и терпеливо ждет.
- После того, как токен обновлен, запрос API повторится.
Теперь представьте, что это делается из более чем одного места в приложении.
Как я его решаю
То, что я обычно делаю, это хранить учетные данные в NSUserDefaults
(если меня не интересует безопасность этих учетных данных - очевидно, лучше использовать цепочку ключей), а затем есть метод для объекта глобального менеджера (singleton), который обновляется войдите в систему, используя эти учетные данные, когда я замечаю, что сессия истекло. Этот глобальный менеджер отключает уведомления при изменении состояния входа в систему, чтобы другие части приложения могли знать, когда они должны повторить запрос после сбоя из-за истечения срока действия сеанса.
То, что я не чувствую, является правильным
Ну, мне просто никогда не нравилась обработка конечной машины объекта-менеджера. Каждое место, которое выполняет запрос, должно сохранить некоторое состояние, чтобы знать, что обновление для входа происходит и повторить запрос после того, как логин был обновлен. Там также проблема о том, что делать, если обновление завершается неудачно, потому что пароль сейчас не так (пользователь изменил его, возможно) - вы, вероятно, не хотите полностью выходить из системы и уничтожать все пользовательское состояние приложения, потому что вы можете просто быть в состоянии запросить новый пароль и продолжить работу по-прежнему. Но глобальный менеджер на самом деле не связан с пользовательским интерфейсом, поэтому ему сложно обрабатывать пользовательский интерфейс, запрашивая новый логин.
Что я хочу знать в ответах
Я понимаю, что этот вопрос особенно расплывчатый и концептуальный (я все еще думаю, что это нормально, чтобы быть на StackOverflow, хотя?), но я просто хотел бы узнать, как другие люди решают эту проблему. Просто объясните, как вы собираетесь обрабатывать истечение сеанса, повторите неудавшиеся запросы со всего приложения и попросите пользователя ввести новые учетные данные, если обновление не работает.
Я думаю, что суть всего этого вопроса:
Где поставить логику повторения запросов, которые не удались из-за истечения сеанса. Я вижу, что эти места есть варианты:
- На уровне контроллера представления (т.е. держите флаг, чтобы сказать, что нам нужно повторить последний запрос после завершения обновления для входа в систему).
- На уровне запроса API (т.е. инкапсулируйте запрос API в объект, который знает, чтобы повторить попытку после того, как логин был обновлен).
- На глобальном уровне диспетчера входа (т.е., возможно, взять блок, когда вызывается
refreshLogin
, который выполняется после того, как логин был обновлен).