Files

81 lines
5.9 KiB
Markdown
Raw Permalink Normal View History

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
---
При создании этого документа использовался ИИ.