Система аутентификации Microsoft
Эта системы аутентификации реализует новый процесс аутентификации на основе Azure, который применим ко всем версиям Minecraft, которые в настоящее время обслуживаются.
Подготовка
Поскольку новый процесс аутентификации использует метод аутентификации на основе Azure. Поэтому, прежде чем начать, убедитесь, что вы завершили конфигурацию приложения Azure.
После завершения регистрации приложения Azure убедитесь, что вы завершили инициализацию аутентификатора Microsoft в точке входа программы.
Настройка метода предоставления кэшированных учетных данных
Из-за особенностей этой системи аутентификации разработчикам необходимо сохранять токен обновления и время истечения срока действия, возвращаемые при первой аутентификации, чтобы помочь аутентификатору завершить аутентификацию. При аутентификации аутентификатор сначала вызовет этот метод, чтобы проверить действительность локального кэша токенов. Если локальный токен все еще действителен, результат аутентификации будет возвращен напрямую. Если токен, кэшированный локально, истек, разработчику необходимо вручную запросить новый токен, а затем вернуть обновленный токен.
Ниже мы приводим пример реализации этого метода:
public async Task<(bool, GraphAuthResultModel?)> CacheTokenProviderAsync()
{
if (string.IsNullOrEmpty(XBLToken)) return (false, default);
if (string.IsNullOrEmpty(XBLRefreshToken)) return (false, default);
// Рассчитать время истечения срока действия
var expireDate = LastRefreshedTime.AddSeconds(ExpiresIn);
// Если локальный кэшированный токен все еще действителен, вернуть текущий токен напрямую
// В противном случае используйте токен обновления для запроса нового токена
if (expireDate > DateTime.Now)
{
var result = new GraphAuthResultModel
{
ExpiresIn = (int)(expireDate - DateTime.Now).TotalSeconds,
AccessToken = XBLToken,
RefreshToken = XBLRefreshToken
};
return (true, result);
}
// Запросить новый токен входа
var refreshReqDic = new List<KeyValuePair<string, string>>
{
new("client_id", MicrosoftAuthenticator.ApiSettings.ClientId),
new("refresh_token", XBLRefreshToken),
new("grant_type", "refresh_token")
};
using var refreshReq = new HttpRequestMessage(HttpMethod.Post, MicrosoftAuthenticator.MSRefreshTokenRequestUrl)
{
Content = new FormUrlEncodedContent(refreshReqDic)
};
using var refreshRes = await DefaultClient.SendAsync(refreshReq);
var refreshContent = await refreshRes.Content.ReadAsStringAsync();
var refreshModel = MicrosoftAuthenticator.ResolveMSGraphResult(refreshContent,
GraphAuthResultModelContext.Default.GraphAuthResultModel);
if (refreshModel is not GraphAuthResultModel model)
{
if (refreshModel is GraphResponseErrorModel error)
{
// Обработка неудачной операции обновления здесь
}
return (false, default);
}
return (true, model);
}Настройка метода отображения кода аутентификации потока устройства при первом входе
Поскольку мы используем аутентификацию потока устройства для аутентификации учетной записи Microsoft игрока. Поэтому нам нужен дополнительный метод для отображения пользователю одноразового ключа и адреса аутентификации, необходимых для аутентификации потока устройства.
Ниже приведен пример этого метода:
private void DeviceTokenNotifier(DeviceIdResponseModel deviceIdResponseModel)
{
// Отображение полученных данных обратного вызова на внешнем интерфейсе
DeviceCodeResponse = deviceIdResponseModel;
}DeviceIdResponseModel содержит всю информацию, необходимую пользователю для завершения аутентификации:
| Название | Действие |
|---|---|
| UserCode | Ключ, необходимый для аутентификации пользователя |
| VerificationUri | Адрес аутентификации, который пользователи должны посетить для выполнения последующих шагов аутентификации |
| ExpiresIn | Время истечения срока действия кода аутентификации (секунды) |
Ниже вы можете увидеть пример интерфейса отображения:

В этом интерфейсе вам необходимо включить как минимум следующее содержимое:
- Ключ, необходимый для входа
- Конкретный адрес аутентификации
- Краткая подсказка по работе, чтобы помочь пользователям завершить операцию аутентификации
Инициализация аутентификатора
Первая аутентификация
WARNING
Убедитесь, что вы подготовили метод отображения кода аутентификации потока устройства при первом входе перед выполнением следующего процесса, чтобы убедиться, что пользователи могут получить правильную информацию для первого входа!
Инициализация аутентификатора:
var microsoftAuthenticator = new MicrosoftAuthenticator
{
LauncherAccountParser = launcherAccountParser
};В приведенном выше блоке кода замените эти параметры в соответствии с вашей реальной ситуацией:
| Элемент | Описание |
|---|---|
| launcherAccountParser | Для инициализации парсера учетных записей лаунчера см. здесь |
Не первая аутентификация
Не первая аутентификация — это использование кэша токенов, полученного при первой аутентификации, для вторичной аутентификации. В основном он проверяет, действительны ли локальные учетные данные через CacheTokenProviderAsync. Если токен, кэшированный локально, истек, он будет обновлен в этом методе.
Инициализация аутентификатора:
var microsoftAuthenticator = new MicrosoftAuthenticator
{
CacheTokenProvider = CacheTokenProviderAsync,
Email = "[EMAIL]",
LauncherAccountParser = launcherAccountParser
};В приведенном выше блоке кода замените эти параметры в соответствии с вашей реальной ситуацией:
| Элемент | Описание |
|---|---|
| launcherAccountParser | Для инициализации парсера учетных записей лаунчера см. здесь |
| [EMAIL] | Адрес электронной почты учетной записи аутентификации |
TIP
Для инициализации launcherAccountParser (парсера игровых профилей) см. страницу Парсер игровых профилей.
Получение результата аутентификации (первая аутентификация)
После завершения инициализации системи аутентификации вам нужно только вызвать метод аутентификации аутентификатора Microsoft для первоначальной аутентификации учетной записи.
Ниже приведен пример кода аутентификации:
// Получить результат аутентификации
// DeviceTokenNotifier — это метод отображения информации, упомянутый ранее
var authResult = await msAuth.GetMSAuthResult(DeviceTokenNotifier);
if (authResult == null)
{
// Обработка неудачной аутентификации
}
// Разбор полей пользователя из токена Jwt
var claims = JwtTokenHelper.GetTokenInfo(authResult.IdToken);
var email = claims.TryGetValue("email", out var outEmail) ? outEmail : null;
if (string.IsNullOrEmpty(email))
{
// Невозможно разобрать адрес электронной почты пользователя из учетных данных Jwt, рассматривается как сбой аутентификации
// Это, скорее всего, вызвано сбоем конфигурации приложения Azure или Scope
}
// Сохранение необходимой информации о пользователе на локальный диск для подготовки к следующей аутентификации
var msInfoModel = new MSAccountInfoModel
{
XBLToken = authResult.AccessToken,
XBLRefreshToken = authResult.RefreshToken,
ExpiresIn = authResult.ExpiresIn,
Email = email
};Получение результата аутентификации (не первая аутентификация)
После завершения инициализации системи аутентификации вам нужно только вызвать метод аутентификации аутентификатора Microsoft для завершения аутентификации учетной записи.
В асинхронном контексте используйте AuthTaskAsync для завершения аутентификации:
var authResult = await microsoftAuthenticator.AuthTaskAsync(false);В синхронном контексте используйте Auth для завершения аутентификации:
var authResult = microsoftAuthenticator.Auth();Интерпретация результата аутентификации
После завершения метода аутентификации оно вернет результат аутентификации, который является объектом родительского типа AuthResultBase. Все результаты аутентификации содержат значение перечисления AuthStatus, которое напрямую указывает на успех или неудачу аутентификации. Ниже вы можете увидеть интерпретацию результата аутентификации:
Неудачный результат аутентификации
Определив, является ли Error пустым, вы можете легко определить, является ли результат аутентификации, возвращенный системой аутентификации, действительным. Объект Error будет содержать следующие поля, чтобы сообщить вам некоторые подробности:
| Поле | Описание |
|---|---|
| authResult.Error.Cause | Конкретная причина проблемы |
| authResult.Error.Error | Название ошибки |
| authResult.Error.ErrorMessage | Подробная информация об ошибке, может содержать решение |
Успешный результат аутентификации
Если поле Error в результате аутентификации пусто, это означает, что эта аутентификация действительна. Успешный результат аутентификации будет содержать следующую информацию:
| Поле | Описание |
|---|---|
| authResult.Id | Уникальный идентификатор этого имени пользователя, ProjBobcat использует определенный метод генерации для генерации этого идентификатора |
| authResult.AccessToken | Учетные данные авторизации учетной записи пользователя |
| authResult.Profiles | Список доступных ролей для пользователя, может содержать несколько доступных ролей |
| authResult.SelectedProfile | Текущая выбранная роль пользователя, это поле может быть пустым. Если оно пустое, пользователю необходимо предложить выбрать вручную. |
| authResult.User | Сводка информации об учетной записи пользователя, содержит некоторую основную информацию об учетной записи |
| authResult.LocalId | Локальный ID, обычно случайно сгенерированный UUID |
| authResult.RemoteId | Удаленный ID, возвращенный сервером аутентификации, обычно уникальный идентификатор пользователя |
| authResult.XBoxUid | XBox Live UID |
| authResult.Email | Адрес электронной почты, используемый для аутентификации |
| authResult.CurrentAuthTime | Текущее время аутентификации, разработчикам необходимо сохранить это поле, чтобы помочь подтвердить действительность локального кэшированного токена |
| authResult.ExpiresIn | Время истечения срока действия токена (единица измерения: секунды), разработчикам необходимо сохранить это поле, чтобы помочь подтвердить действительность локального кэшированного токена |
| authResult.RefreshToken | Токен обновления, разработчикам необходимо сохранить это поле, чтобы помочь обновить просроченные токены |
| authResult.Skin | URL-адрес скина учетной записи пользователя |
WARNING
Пожалуйста, используйте соответствующие ограничения или шифрование для безопасного хранения конфиденциальных данных, связанных с токенами пользователей. Утечка этой части данных может привести к потерям.