Обновить токены на нескольких устройствах

#refresh-token

#обновить-токен

Вопрос:

У меня есть Api и мобильный клиент. Я использую токены обновления следующим образом:

  1. Пользователь предоставляет учетные данные, Api возвращает токен доступа и токен обновления. Затем токен обновления сохраняется с указанием даты истечения срока действия в таблице users в БД.
  2. Клиент использует некоторые защищенные ресурсы, используя данный токен доступа.
  3. Срок действия токена доступа истекает, поэтому клиент предоставляет свой токен обновления и получает новую пару токенов.
  4. Шаги 2 и 3 повторяются снова и снова.

Проблема: допустим, у пользователя есть 2 устройства, A и B. Он успешно вошел в систему с помощью устройства A, поэтому он получил 2 токена и доволен. Как только пользователь войдет в систему с устройства B, Api отправит ему новую пару токенов, что означает, что новый токен обновления заменит уже заданный токен на устройство A. Теперь пользователь возвращается к устройству A aaa, и оно исчезло (недопустимый токен обновления!), Поэтому он должен снова предоставить учетные данные, чего я, пользователь и вы не хотите.

Предложения: Я нашел 2 подхода к решению проблемы, но поскольку я довольно новичок в этой теме, я не вижу, какая из них является наилучшей практикой:

Подход A: сохраните несколько токенов обновления для каждого пользователя и сохраните идентификатор устройства (все еще не знаю, что именно в случае разных типов клиентов, таких как мобильный, браузерный и настольный клиент!) но в любом случае. При таком подходе, когда пользователь входит в систему с устройства A, Api предоставляет оба токена. Пользователь входит в систему с устройства B, Api предоставляет новую пару токенов. Он возвращается к устройству A, он снова использует свой первый токен (все еще действительный).

Подход B: сохраните 1 токен обновления для каждого пользователя. когда пользователь входит в систему с устройства B, Api отправляет обратно единственный токен обновления (я не должен заботиться об устройствах, если пользователь предоставляет действительные учетные данные, верно?)

Не могли бы вы указать на плюсы и минусы для каждого подхода?

Ответ №1:

Подход A — это обычный способ справиться с этим. Токены доступа / обновления не должны использоваться совместно для разных сеансов / устройств.

Каждый должен получить свою собственную пару. При использовании refresh_token операции срок действия токена обновления, который использовался с этим запросом, должен истекать, а не какие-либо несвязанные.

Комментарии:

1. Какой идентификатор устройства я должен сохранить тогда? Особенно, если у меня несколько клиентов разных типов?

2. Я не знаю, что вы подразумеваете под идентификатором устройства или что это означает в контексте этого вопроса.

3. Если я хочу сохранить несколько токенов обновления и каждый для уникального устройства, как я должен идентифицировать каждое устройство?

4. Да, это звучит разумно. Я бы также рекомендовал еще раз прочитать документацию по OAuth2 и OAuth2.1, если вы давно этого не делали.

5. Я так и сделаю. И последнее: если у меня есть несколько токенов обновления для каждого пользователя, и пользователь отправляет много логинов с действительными учетными данными на разных устройствах, у меня будет много токенов, сохраненных в БД. Теперь, если пользователь выполнит выход из системы, я удалю этот токен. Если он захочет глобального выхода из системы, я удалю все токены обновления для этого пользователя. Что, если он войдет в систему на таком количестве устройств и никогда не выйдет из системы? срок действия токенов в конечном итоге истечет, но они просто висят там в БД! должен ли у меня быть рабочий, который запускается, скажем, один раз в день, чтобы очистить все токены с истекшим сроком действия из базы данных?

Ответ №2:

Недавно я решил эту проблему с помощью следующего подхода:

Каждая запись пользовательской базы данных имеет refreshTokens поле, представляющее собой RefreshTokenObject массив следующего формата: {token: <tokenUUID>, creationDate: Date}

Вход

Каждый раз, когда пользователь входит в систему, RefreshTokenObject к существующему списку объектов токенов добавляется новый.

Обновление токена

Серверная часть выполняет a map для RefreshTokenObjects записи, заменяя найденный RefreshTokenObject новый токен и дату создания, отправляя новый токен обновления доступа пользователю. Если токен не найден, сервер возвращает 401 с refresh token expired в теле, предлагая интерфейсу повторно выполнить вход.

Выход

Интерфейс будет отправлять сообщения в /api/login/signout with body { userId: <id>, refreshToken: <tokenUUID> } каждый раз, когда происходит выход из системы. Затем серверная часть удалит соответствующий токен, если он будет найден в списке. Примечание: я решил не возвращать серверную часть 404, если refreshToken не был найден; это чрезвычайно странный случай и приведет к повторному входу в систему только в худшем случае.

Рекомендации

Поскольку многие базы данных имеют ограничение по размеру документа, вы должны быть осторожны с постоянно растущими массивами. Я реализовал clearOldTokens функцию, которая запускается при каждом входе в систему, выходе из системы или обновлении. Он просто сравнивает поле всех существующих токенов creationDate с текущим временем, и, если срок действия токена истек, он удалит этот токен из refreshTokenObjects массива пользователя.

Еще разумнее использовать идентификатор устройства и тому подобное, чтобы отслеживать это; просто больше работы.

Комментарии:

1. Это не отвечает на вопрос о нескольких устройствах и нескольких обновлениях.

2. @VictorMartinezCalvo Это так; если вы прочитаете мой предыдущий пост, вы увидите, что мой метод включает в себя вызываемый массив refreshTokens , который содержит массив токенов обновления для различных устройств.