From f3ffd362b5c3d991f85b0cf7d0c262a741347ca5 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 9 Mar 2021 12:34:39 +0100 Subject: [PATCH] Update an article about Minecraft authentication --- source/ru/minecraft-auth.rst | 122 ++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 44 deletions(-) diff --git a/source/ru/minecraft-auth.rst b/source/ru/minecraft-auth.rst index 1fb3036..3e86619 100644 --- a/source/ru/minecraft-auth.rst +++ b/source/ru/minecraft-auth.rst @@ -16,7 +16,7 @@ * Сервер всегда отвечает JSON данными, кроме случаев системных ошибок и ответов на legacy запросы. Учитывайте это для отображения пользователю правильного сообщения об ошибке. -* В случае стандартной ошибки, вы получилите следующие данные: +* В случае стандартной ошибки, вы получите следующие данные: .. code-block:: javascript @@ -49,52 +49,78 @@ Авторизация в лаунчере ====================== -В этом разделе описана авторизация для лаунчера или любой другой настольной программы, которой необходимо получить -accessToken для игрового клиента Minecraft. Важно понимать, что этот accessToken не имеет ничего общего с accessToken, -получаемым при oAuth авторизации - это два абсолютно разных ключа. +В этом разделе описана авторизация для игрового лаунчера и описывает действия, необходимые для получения ``accessToken`` для игрового клиента Minecraft. В результате авторизации будет получен JWT-токен с :ref:`правами доступа ` ``minecraft_server_session``. -Все запросы выполняются на подуровень /auth POST запросом. +.. attention:: Мы рекомендуем использовать :doc:`протокол авторизации OAuth 2.0 ` с запросом :ref:`прав доступа ` ``minecraft_server_session``, как более безопасный и удобный для пользователя метод. -.. function:: /auth/authenticate +.. function:: POST /auth/authenticate - Непосредственная авторизация пользователя, используя его логин (ник или e-mail) и пароль. + Непосредственная авторизация пользователя, используя его логин (ник или E‑mail), пароль и токен двухфакторной аутентификации. - :param string username: Никнейм пользователя или его e-mail (более предпочтительно). - :param string password: Пароль пользователя. + :param string username: Никнейм пользователя или его E‑mail (более предпочтительно). + :param string password: Пароль пользователя или комбинация ``пароль:токен``. :param string clientToken: Уникальный токен лаунчера пользователя. + :param bool requestUser: Если поле передано как ``true``, то в ответе сервера будет присутствовать поле ``user``. - Успешный ответ: + Система аккаунтов Ely.by поддерживает защиту пользователей посредством двухфакторной аутентификации. В оригинальном протоколе авторизации Mojang не предусмотрено возможности для передачи TOTP-токенов. Для решения этой проблемы и сохранения совместимости с реализацией сервера `Yggdrasil `_, мы предлагаем передавать токен в поле ``password`` в формате ``пароль:токен``. + + К сожалению, не все пользователи осведомлены об этой возможности, поэтому будет лучше при получении ошибки о защищённости аккаунта пользователя двухфакторной аутентификацией явно запросить у него токен и склеить его программно. + + Логика следующая: + + #. Если пользователь указал верные логин и пароль, но для его аккаунта включена двухфакторная аутентификация, вы получите ответ с ``401`` статусом и следующим содержимым: + + .. code-block:: javascript + + { + "error": "ForbiddenOperationException", + "errorMessage": "Account protected with two factor auth." + } + + #. При получении этой ошибки, необходимо запросить у пользователя ввод TOTP‑токена, после чего повторить запрос на авторизацию с теми же учётными данными, добавив к паролю постфикс в виде ``:токен``, где ``токен`` — это значение, введённое пользователем. + + Если пароль пользователя был "password123", а токен "123456", то после склейки поле ``password`` примет значение "password123:123456". + + #. Если в результате этих действий вы получите ответ с ``401`` статутом и ``errorMessage`` "Invalid credentials. Invalid email or password.", то это будет свидетельствовать о том, что переданный токен неверен и его нужно перезапросить у пользователя. + + Если все данные будут переданы верно, вы получите следующий ответ: .. code-block:: javascript { - 'accessToken': "Длинная_строка_содержащая_access_token", - 'clientToken': "Переданный_в_запросе_client_token", - 'availableProfiles': {}, /* См. ниже */ - 'selectedProfile': { - 'id': "Длинная_строка_с_uuid_пользователя", - 'name': "Текущий_nickname_пользователя", - 'legacy': false + "accessToken": "Длинная_строка_содержащая_access_token", + "clientToken": "Переданный_в_запросе_client_token", + "availableProfiles": [ + { + "id": "UUID_пользователя_без_дефисов", + "name": "Текущий_username_пользователя" + } + ], + "selectedProfile": { + "id": "UUID_пользователя_без_дефисов", + "name": "Текущий_username_пользователя" + }, + "user": { /* Только если передан параметр requestUser */ + "id": "UUID_пользователя_без_дефисов", + "username": "Текущий_username_пользователя", + "properties": [ + { + "name": "preferredLanguage", + "value": "ru" + } + ] } } - **availableProfiles** содержит в себе массив с одним элементом, таким же, как и selectedProfile. Добавлено только для - соответствия оригинальному протоколу и на деле не используется самими Mojang. +.. function:: POST /auth/refresh - Касательно параметра **legacy** в selectedProfile в оригинальном протоколе явно не даны пояснения на счёт этого - параметра, но сказано, что обычно он в false. Возможно, он как-то используется официальным лаунчером. + Обновляет валидный ``accessToken``. Этот запрос позволяет не хранить на клиенте его пароль, а оперировать только сохранённым значением ``accessToken`` для практически бесконечной возможности проходить авторизацию. -.. function:: /auth/refresh - - Обновляет валидный accessToken. Этот запрос позволяет не хранить на клиенте его пароль, а оперировать только сохранённым - значением accessToken для практически бесконечной возможности проходить авторизацию. - - :param string accessToken: Уникальный ключ, полученый после авторизации. + :param string accessToken: Уникальный ключ, полученный после авторизации. :param string clientToken: Уникальный идентификатор клиента, относительно которого получен accessToken. + :param bool requestUser: Если поле передано как ``true``, то в ответе сервера будет присутствовать поле ``user``. - .. note:: В оригинальном протоколе так же передаётся значение selectedProfile, но на деле от него мало что зависит и - для идентификации пользователя достаточно только этих двух параметров. Наш сервер не обидится, увидив его - - он просто его проигнорирует. + .. note:: В оригинальном протоколе так же передаётся значение ``selectedProfile``, но в реализации Mojang он не влияет ни на что. Наша реализация сервера авторизации игнорирует этот параметр и опирается на значения ``accessToken`` и ``clientToken``. В случае получения какой-либо предусмотренной ошибки, следует заново запросить пароль пользователя и произвести обычную авторизацию. @@ -104,24 +130,32 @@ accessToken для игрового клиента Minecraft. Важно пон .. code-block:: javascript { - 'accessToken': "Новая_длинная_строка_ содержащая_access_token", - 'clientToken': "Переданный_в_запросе_client_token", - 'selectedProfile': { - 'id': "Длинная_строка_с_uuid_пользователя", - 'name': "Текущий_nickname_пользователя", - 'legacy': false + "accessToken": "Новая_длинная_строка_ содержащая_access_token", + "clientToken": "Переданный_в_запросе_client_token", + "selectedProfile": { + "id": "UUID_пользователя_без_дефисов", + "name": "Текущий_username_пользователя" + }, + "user": { /* Только если передан параметр requestUser */ + "id": "UUID_пользователя_без_дефисов", + "username": "Текущий_username_пользователя", + "properties": [ + { + "name": "preferredLanguage", + "value": "ru" + } + ] } } -.. function:: /auth/validate +.. function:: POST /auth/validate Этот запрос позволяет проверить валиден ли указанный accessToken или нет. Этот запрос не обновляет токен и его время жизни, а только позволяет удостовериться, что он ещё действительный. - :param string accessToken: Уникальный ключ, полученый после авторизации. + :param string accessToken: Токен доступа, полученный после авторизации. - Успешным ответом будет являться пустое тело. При ошибке будет получен **400** или **401** статус. Пример ответа сервера - при отправке истёкшего токена: + Успешным ответом будет являться пустое тело. При ошибке будет получен **400** или **401** статус. Пример ответа сервера при отправке истёкшего токена: .. code-block:: javascript @@ -130,23 +164,23 @@ accessToken для игрового клиента Minecraft. Важно пон "errorMessage": "Token expired." } -.. function:: /auth/signout +.. function:: POST /auth/signout Этот запрос позволяет выполнить инвалидацию всех выданных пользователю токенов. - :param string username: Никнейм пользователя или его e-mail (более предпочтительно). + :param string username: Никнейм пользователя или его E-mail (более предпочтительно). :param string password: Пароль пользователя. Успешным ответом будет являться пустое тело. Ориентируйтесь на поле **error** в теле ответа. -.. function:: /auth/invalidate +.. function:: POST /auth/invalidate Запрос позволяет инвалидировать accessToken. В случае, если переданный токен не удастся найти в хранилище токенов, ошибка не будет сгенерирована и вы получите успешный ответ. Входные параметры: - :param string accessToken: Уникальный ключ, полученый после авторизации. + :param string accessToken: Уникальный ключ, полученный после авторизации. :param string clientToken: Уникальный идентификатор клиента, относительно которого получен accessToken. Успешным ответом будет являться пустое тело. Ориентируйтесь на поле **error** в теле ответа.