2026-09-03 09:16:56 +03:00
|
|
|
|
# MsaAuthService
|
|
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
`msaauthservice.h`, `msaauthservice.cpp`
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
Вход через аккаунт Microsoft, то есть с лицензионной копией игры. Цепочка такая же, как у
|
|
|
|
|
|
официального лаунчера: OAuth2 → Xbox Live → XSTS → Minecraft Services → проверка лицензии →
|
|
|
|
|
|
профиль. Результат приходит в `AuthResult` из [AuthService](AuthService.md).
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
Окно входа сервис не показывает. Страницу Microsoft открывает
|
|
|
|
|
|
[MicrosoftLoginDialog](../qml/MicrosoftLoginDialog.md), а сервис даёт адрес этой страницы и умеет
|
|
|
|
|
|
узнать адрес возврата. Класс компилируется всегда, но без Qt WebEngine показать страницу нечем, и
|
|
|
|
|
|
[LauncherBackend](LauncherBackend.md) сразу отвечает ошибкой.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
## Чьё это приложение
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
Сейчас используется `client_id` официального лаунчера Mojang (`00000000402b5328`). Это старое
|
|
|
|
|
|
приложение Live Connect, поэтому и адреса от `login.live.com`:
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
| Константа | Значение |
|
|
|
|
|
|
|-----------|----------|
|
|
|
|
|
|
| `kAuthorizeUrl` | `https://login.live.com/oauth20_authorize.srf` |
|
|
|
|
|
|
| `kTokenUrl` | `https://login.live.com/oauth20_token.srf` |
|
|
|
|
|
|
| `kRedirectUri` | `https://login.live.com/oauth20_desktop.srf` |
|
|
|
|
|
|
| `kScope` | `service::user.auth.xboxlive.com::MBI_SSL` |
|
|
|
|
|
|
| `kRpsTicketPrefix` | пусто |
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
Это временное решение. Чтобы перейти на своё приложение в Azure (с включённым «Allow public client
|
|
|
|
|
|
flows»), меняются эти шесть констант. Что именно подставить, написано в комментарии в начале
|
|
|
|
|
|
`msaauthservice.cpp`. Главное, что легко пропустить: у нового приложения в `RpsTicket` нужна
|
|
|
|
|
|
приставка `d=`.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
`clientId()` отдаёт этот id наружу. Бэкенд подставляет его в `${clientid}`, потому что официальный
|
|
|
|
|
|
лаунчер передаёт туда id приложения, а не случайный токен.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
## Окно входа
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
`authorizationUrl()` — адрес страницы входа с `client_id`, `response_type=code`, `redirect_uri`,
|
|
|
|
|
|
`scope` и `prompt=select_account`. Последний параметр нужен, чтобы при повторном входе можно было
|
|
|
|
|
|
выбрать другой аккаунт.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
`matchRedirect(url, &code, &error)` возвращает `true`, только если хост и путь совпадают с
|
|
|
|
|
|
`kRedirectUri`. Код или ошибка ищутся сначала в query, потом во фрагменте. В `error` попадает
|
|
|
|
|
|
`error_description`, а если его нет, то `error`. Эта проверка сделана в C++, а не в QML, чтобы она
|
|
|
|
|
|
всегда совпадала с тем адресом, который сервис сам передаёт в `redirect_uri`.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
## Цепочка
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
`loginWithCode(code, callback)` меняет код на токен (`grant_type=authorization_code`).
|
|
|
|
|
|
`loginWithRefreshToken(refreshToken, callback)` делает то же по refresh-токену. Дальше путь общий:
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
1. **Токен Microsoft.** Форма на `kTokenUrl`. Из ответа берутся `access_token` и `refresh_token`.
|
|
|
|
|
|
2. **Xbox Live.** `user.auth.xboxlive.com/user/authenticate`, `RpsTicket` = приставка + токен
|
|
|
|
|
|
Microsoft.
|
|
|
|
|
|
3. **XSTS.** `xsts.auth.xboxlive.com/xsts/authorize` для `rp://api.minecraftservices.com/`. При 401
|
|
|
|
|
|
код `XErr` переводится в понятный текст: нет профиля Xbox, страна не поддерживается, нужна
|
|
|
|
|
|
проверка возраста, детский аккаунт без разрешения взрослого. Отсюда же берутся `uhs` и `xid`
|
|
|
|
|
|
(он станет `xuid`).
|
|
|
|
|
|
4. **Minecraft Services.** `login_with_xbox` с `XBL3.0 x=<uhs>;<xsts>`. В ответе токен Minecraft и
|
|
|
|
|
|
`expires_in`, обычно сутки; от него считается `expiresAt`.
|
|
|
|
|
|
5. **Лицензия.** `entitlements/mcstore`. Результат только запоминается и сам вход не останавливает.
|
|
|
|
|
|
6. **Профиль.** `minecraft/profile`. Ответы 404 и 401 означают, что профиля нет: выставляется
|
|
|
|
|
|
`licenseMissing`. Текст ошибки зависит от шага 5. Если игра куплена, значит, игрок ещё не выбрал
|
|
|
|
|
|
ник. Если не куплена, значит, лицензии нет.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
`userType` = `msa`, `clientToken` = id приложения.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
Каждый шаг испускает `progress(message)` до отправки запроса. Таймаут на каждый запрос 20 секунд,
|
|
|
|
|
|
повторных попыток нет. Сетевая ошибка и отказ сервера дают разные тексты.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
Refresh-токен Microsoft живёт намного дольше суточного токена Minecraft, поэтому при обычном
|
|
|
|
|
|
запуске окно входа не нужно: бэкенд вызывает `loginWithRefreshToken()`. Если Microsoft не вернул
|
|
|
|
|
|
новый refresh-токен, бэкенд оставляет старый.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
## Колбэки
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
Колбэк вызывается один раз в GUI-потоке. Шаги вызываются из колбэков предыдущих. Если удалить
|
|
|
|
|
|
сервис посреди цепочки, она оборвётся вместе с менеджером сети, и колбэк не вызовется.
|
2026-09-03 09:16:56 +03:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
При создании этого документа использовался ИИ.
|