# AuthService ## Обзор класса `Minecraft_launcher` поддерживает три способа входа: офлайн-профиль без пароля, учётную запись Ely.by и учётную запись Microsoft. `AuthService` закрывает первые два: это Yggdrasil-клиент Ely.by плюс офлайн-режим. За третий отвечает [MsaAuthService](MsaAuthService.md). Результат любого способа — структура `AuthResult`, объявленная в этом же заголовке. Она содержит ровно то, что подставляется в аргументы запуска вида `${auth_*}`, поэтому дальше запуск игры идёт по общему пути независимо от того, как пользователь вошёл. Класс также умеет скачивать `authlib-injector` — библиотеку, которая перенаправляет обращения игры к серверу авторизации на Ely.by. ## Место в проекте и зависимости Экземпляр создаётся и принадлежит [LauncherBackend](LauncherBackend.md); других владельцев нет. Заголовок подключает [MsaAuthService](MsaAuthService.md) — ради общей структуры `AuthResult` — и [GameLauncher](GameLauncher.md) через поля `LaunchOptions`, которые заполняются из результата авторизации. Требования сборки: `Qt6::Core` (`QDateTime`, `QJsonObject`, `QString`) и `Qt6::Network` (`QNetworkAccessManager`). ## Иерархия и роль Наследует `QObject`: даёт мета-объектную систему, сигнал `progress` и владение по родителю. Виртуальных методов базового класса не переопределяет. ## Публичные структуры ### AuthResult Результат авторизации — то, что подставляется в `${auth_*}` аргументы запуска. | Поле | Тип | Описание | |------|-----|----------| | `ok` | `bool` | Авторизация удалась | | `twoFactorRequired` | `bool` | Ely.by отклонил пароль с пометкой two factor — нужен одноразовый код | | `licenseMissing` | `bool` | Вход в Microsoft прошёл, но копии игры на аккаунте нет. Обрабатывается отдельно от прочих ошибок, потому что чинится только покупкой | | `error` | `QString` | Текст ошибки, когда `ok` равен `false` | | `playerName` | `QString` | Подставляется в `${auth_player_name}` | | `uuid` | `QString` | Подставляется в `${auth_uuid}`; hex без дефисов | | `accessToken` | `QString` | Подставляется в `${auth_access_token}` | | `clientToken` | `QString` | Подставляется в `${clientid}` | | `userType` | `QString` | Подставляется в `${user_type}`; принимает значения `legacy` (офлайн), `msa` (Microsoft) и `ELYBY` | | `refreshToken` | `QString` | Только для аккаунтов Microsoft: продлевает сессию без ввода пароля | | `xuid` | `QString` | Только для Microsoft; подставляется в `${auth_xuid}` | | `expiresAt` | `QDateTime` | Только для Microsoft: UTC-время, когда протухает `accessToken` | ## Псевдонимы типов `AuthService::Callback` — `std::function`. Все сетевые методы асинхронные: колбэк вызывается ровно один раз и всегда в потоке GUI. ## Публичные методы #### explicit AuthService(QObject \*parent = nullptr) Создаёт сервис и его `QNetworkAccessManager`. Конструктор помечен `explicit`. #### static AuthResult offline(const QString &nickname) Готовит результат для офлайн-профиля без единого сетевого запроса. UUID выводится из ника так же, как это делает сам Minecraft в офлайне: `UUID.nameUUIDFromBytes(("OfflinePlayer:" + name) .getBytes(UTF_8))`. Благодаря этому один и тот же ник всегда даёт один и тот же UUID, и прогресс на сервере не теряется. #### static QString generateClientToken() Случайный `clientToken` лаунчера. Генерируется один раз на профиль и хранится вместе с ним: Yggdrasil связывает выданный `accessToken` именно с этим значением. #### void loginElyBy(const QString &login, const QString &password, const QString &clientToken, const QString &accessToken, Callback callback) Полный цикл входа в Ely.by: сначала проверка имеющегося токена, затем его продление, и только при неудаче — авторизация по паролю. Пароль можно оставить пустым, если уже есть рабочий `accessToken`, — тогда пользователю не придётся вводить его заново. По ходу работы испускает `progress` с описанием текущего шага. Результат приходит в `callback` один раз; при ответе с пометкой двухфакторной аутентификации в нём выставлен `twoFactorRequired`, и вызывающий код должен спросить у пользователя код и продолжить через `loginElyByWithTotp()`. #### void loginElyByWithTotp(const QString &login, const QString &password, const QString &totp, const QString &clientToken, Callback callback) Повтор авторизации с одноразовым кодом двухфакторной аутентификации. Пароль и код объединяются в одно поле в формате «пароль:код», как того требует Ely.by. #### void ensureAuthlibInjector(const QString &targetDir, std::function<void(const QString &path, const QString &error)> callback) Скачивает `authlib-injector` в `targetDir`, если его там ещё нет. Колбэк получает либо путь к готовому jar, либо текст ошибки — заполнено всегда ровно одно из двух. Библиотека нужна только для профилей Ely.by: она подключается к JVM аргументом `-javaagent` и перенаправляет обращения игры к серверу авторизации. ## Сигналы #### progress(const QString &message) Описание текущего шага авторизации. Испускается по ходу всех сетевых операций. Обработчик показывает сообщение пользователю: в главном окне лаунчера оно попадает в плашку статуса и держится до следующего сообщения, потому что шаг может занять заметное время. ## Владение и время жизни Класс наследует `QObject` и принимает `parent` в конструкторе — родитель его и удалит. `QNetworkAccessManager` создаётся в конструкторе с сервисом в роли родителя и уничтожается вместе с ним. Колбэки захватываются по значению и живут до своего единственного вызова. Уничтожение сервиса во время незавершённого запроса отменяет запрос вместе с менеджером сети — колбэк в этом случае не вызывается, поэтому захватывать в него сырые указатели на объекты с меньшим временем жизни, чем у сервиса, нельзя. ## Потокобезопасность Только поток GUI. Все сетевые методы асинхронные, и их колбэки вызываются в том же потоке, в котором создан сервис. Собственной синхронизации в классе нет. ## Взаимодействие с другими классами `LauncherBackend` вызывает методы входа при запуске игры и переправляет сигнал `progress` в интерфейс. Полученный `AuthResult` он раскладывает по полям `LaunchOptions`, которые уходят в [GameLauncher](GameLauncher.md). Путь, возвращённый `ensureAuthlibInjector()`, попадает в поле `authlibInjectorPath` тех же параметров запуска. Сохранением токенов между запусками занимается `LauncherBackend`: сам сервис ничего не пишет на диск, кроме скачанного jar. ## Внешнее взаимодействие **Сеть, исходящие запросы.** Класс общается с сервером авторизации Ely.by через `QNetworkAccessManager`. Формат — JSON поверх HTTPS, запросы инициирует всегда лаунчер. Внутренний помощник `postJson()` разделяет три исхода: успешный ответ, ответ с кодом ошибки и транспортную ошибку — последняя отдаётся отдельным параметром, чтобы отличить недоступную сеть от отказа сервера. Отдельным каналом идёт загрузка `authlib-injector` — обычная HTTPS-загрузка файла в `targetDir`. Повторных попыток при неудаче класс не делает: решение о повторе принимает вызывающий код. Все сигналы и колбэки приходят в поток GUI. ## Пример использования ```cpp auto *auth = new AuthService(this); connect(auth, &AuthService::progress, this, &Backend::showStatus); auth->loginElyBy(profile.login, profile.password, profile.clientToken, profile.accessToken, [this](const AuthResult &result) { if (result.twoFactorRequired) { emit twoFactorRequired(m_pendingProfileName); return; } if (!result.ok) { emit launchError(result.error); return; } continueLaunch(result); }); ``` --- При создании этого документа использовался ИИ.