Вызов веб-API из мобильного приложения

После того как приложение авторизует пользователя и получит маркеры, библиотека проверки подлинности Microsoft (MSAL) предоставляет информацию о пользователе, среде пользователя и выданных маркерах. Эти значения можно использовать для вызова веб-API или отображения приветственного сообщения для пользователя.

В этой статье мы сначала рассмотрим результат, полученный MSAL. Затем мы рассмотрим, как использовать маркер доступа из AuthenticationResult или result для вызова защищенного веб-API.

Результат, полученный MSAL

MSAL предоставляет следующие значения:

  • AccessToken вызывает защищенные веб-API в запросе носителя HTTP.
  • IdToken содержит полезную информацию об авторизованном пользователе. Эта информация включает имя пользователя, домашнего клиента и уникальный идентификатор хранилища.
  • ExpiresOn — это время истечения срока действия маркера. MSAL обрабатывает автоматическое обновление приложения.
  • TenantId — это идентификатор клиента, где выполнил вход пользователь. Для гостевых пользователей в Microsoft Entra B2B это значение определяет клиент, в котором пользователь вошел в систему. Это значение не идентифицирует домашний клиент пользователя.
  • Scopes обозначает области, предоставленные вместе с вашим маркером. Предоставленные области могут представлять собой подмножество запрошенных вами областей.

MSAL также предоставляет абстракцию значения Account. Значение Account представляет учетную запись, с которой выполнил вход текущий пользователь:

  • HomeAccountIdentifier обозначает домашний клиент пользователя.
  • UserName — это предпочитаемое пользователем имя пользователя. Для пользователей B2C Azure AD это значение может быть пустым.
  • AccountIdentifier обозначает авторизованного пользователя. В большинстве случаев это значение совпадает со значением HomeAccountIdentifier (кроме случаев, когда пользователь является гостем в другом клиенте).

Вызов API

Получив маркер доступа, можно вызывать веб-API. Ваше приложение будет использовать этот токен для создания HTTP-запроса с последующим выполнением этого запроса.

Android

        RequestQueue queue = Volley.newRequestQueue(this);
        JSONObject parameters = new JSONObject();

        try {
            parameters.put("key", "value");
        } catch (Exception e) {
            // Error when constructing.
        }
        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, MSGRAPH_URL,
                parameters,new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // Successfully called Graph. Process data and send to UI.
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // Error.
            }
        }) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> headers = new HashMap<>();

                // Put access token in HTTP request.
                headers.put("Authorization", "Bearer " + authResult.getAccessToken());
                return headers;
            }
        };

        request.setRetryPolicy(new DefaultRetryPolicy(
                3000,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        queue.add(request);

MSAL для iOS и MacOS

Методы получения маркеров возвращают объект MSALResult. MSALResult предоставляет свойство accessToken. Можно использовать accessToken для вызова веб-API. Добавьте это свойство в заголовок авторизации HTTP, прежде чем отправлять запрос на доступ к защищенному веб-API.

NSMutableURLRequest *urlRequest = [NSMutableURLRequest new];
urlRequest.URL = [NSURL URLWithString:"https://contoso.api.com"];
urlRequest.HTTPMethod = @"GET";
urlRequest.allHTTPHeaderFields = @{ @"Authorization" : [NSString stringWithFormat:@"Bearer %@", accessToken] };

NSURLSessionDataTask *task =
[[NSURLSession sharedSession] dataTaskWithRequest:urlRequest
     completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {}];
[task resume];
let urlRequest = NSMutableURLRequest()
urlRequest.url = URL(string: "https://contoso.api.com")!
urlRequest.httpMethod = "GET"
urlRequest.allHTTPHeaderFields = [ "Authorization" : "Bearer \(accessToken)" ]

let task = URLSession.shared.dataTask(with: urlRequest as URLRequest) { (data: Data?, response: URLResponse?, error: Error?) in }
task.resume()

Xamarin

Свойства объекта AuthenticationResult в MSAL.NET

Для получения маркеров методы возвращают объект AuthenticationResult. Для асинхронных методов возвращается Task<AuthenticationResult>.

MSAL.NET AuthenticationResult предоставляет следующие параметры:

  • AccessToken — обеспечивает для веб-API доступ к ресурсам. Это строковый параметр, который обычно представляет собой маркер JWT в кодировке Base-64. Клиент никогда не должен считывать содержимое маркера доступа. Стабильность формата не гарантируется, и маркер может быть зашифрован для конкретного ресурса. Написание кода, который зависит от содержимого маркера доступа на стороне клиента, является одним из основных источников для ошибок и сбоев в логике клиента. Дополнительные сведения см. в разделе Маркеры доступа.
  • IdToken — предназначается для пользователей. Этот параметр является зашифрованным маркером JWT. Дополнительные сведения см. в разделе Маркеры идентификации.
  • ExpiresOn — сообщает дату и время истечения срока действия маркера.
  • TenantId — содержит сведения о клиенте, в котором был найден пользователь. Для гостевых пользователей в сценариях Microsoft Entra B2B идентификатор клиента является гостевым клиентом, а не уникальным клиентом. При предоставлении маркера для пользователя в объекте AuthenticationResult также содержится информация об этом пользователе. Для потоков конфиденциальных клиентов, где маркеры запрашиваются без пользователя для приложения, эта информация о пользователе имеет значение NULL.
  • Scopes — обозначает области, для которых выдан маркер.
  • Уникальный идентификатор пользователя.

IAccount

В MSAL.NET понятие учетной записи определяется через интерфейс IAccount. Такое радикальное изменение обеспечивает правильную семантику. Один и тот же пользователь может иметь несколько учетных записей в разных каталогах Microsoft Entra. Также MSAL.NET предоставляет более подробные сведения в сценариях с гостевым входом благодаря добавлению информации о домашней учетной записи. Структура интерфейса IAccount представлена на следующей схеме.

IAccount interface structure

Класс AccountId определяет учетную запись в конкретном клиенте с помощью свойств, приведенных в следующей таблице.

Свойство Description
TenantId Строковое представление идентификатора GUID, которое является идентификатором клиента, где находится учетная запись.
ObjectId Строковое представление идентификатора GUID, являющееся идентификатором пользователя, которому принадлежит учетная запись в клиенте.
Identifier Уникальный идентификатор для учетной записи. Identifier является объединением ObjectId и TenantId, разделенных запятой. Для этих значений шифрование Base 64 не применяется.

Интерфейс IAccount предоставляет сведения об одной учетной записи. Один и тот же пользователь может быть в разных клиентах, это означает, что у пользователя может быть несколько учетных записей. Компоненты этого интерфейса представлены в следующей таблице.

Свойство Description
Username Строка с отображаемым значением в формате UserPrincipalName (UPN), например john.doe@contoso.com. Эта строка может иметь значение NULL, в отличие от свойств HomeAccountId и HomeAccountId.Identifier, у которых не может быть значения NULL. Это свойство заменяет свойство DisplayableId интерфейса IUser из предыдущих версий MSAL.NET.
Environment Строка с поставщиком удостоверений для этой учетной записи, например login.microsoftonline.com. Это свойство заменяет свойство IdentityProvider интерфейса IUser, за исключением того, что в свойстве IdentityProvider также содержались сведения о клиенте в дополнение к информации об облачной среде. Содержащееся здесь значение определяет только узел.
HomeAccountId Идентификатор домашней учетной записи пользователя. Это свойство однозначно идентифицирует пользователя в клиентах Microsoft Entra.

Использование маркера для вызова защищенного API

После того как AuthenticationResult возвращается MSAL в переменную result, ее нужно добавить в HTTP-заголовок авторизации перед тем, как делать вызов для доступа к защищенному веб-API.

httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

// Call the web API.
HttpResponseMessage response = await _httpClient.GetAsync(apiUri);
...
}

Выполнение нескольких запросов API

Чтобы вызвать один и тот же API несколько раз или вызвать несколько API, при разработке приложения следует учитывать следующие моменты.

  • Добавочное согласие. Платформа удостоверений Microsoft позволяет приложениям получать согласие пользователя, когда необходимы разрешения, а не все сразу во время запуска. Всякий раз, когда ваше приложение готово вызвать API, оно должно запрашивать только необходимые ему области.

  • Условный доступ. При отправке нескольких запросов API в некоторых сценариях потребуется обеспечить выполнение дополнительных требований к условному доступу. Требования могут увеличиваться таким образом, если первый запрос не имеет политик условного доступа, и приложение пытается автоматически получить доступ к новому API, которому требуется условный доступ. Для решения этой проблемы необходимо перехватывать ошибки, генерируемые такими автоматическими запросами, и быть готовым к выполнению интерактивного запроса. Дополнительные сведения см. в руководстве по условному доступу.

Чтобы вызвать несколько API для одного пользователя после получения маркера для этого пользователя, можно не требовать от него предоставления учетных данных. Достаточно вызывать AcquireTokenSilent, чтобы получить маркер:

var result = await app.AcquireTokenXX("scopeApi1")
                      .ExecuteAsync();

result = await app.AcquireTokenSilent("scopeApi2")
                  .ExecuteAsync();

Взаимодействие необходимо, если:

  • Пользователь предоставил согласие для первого API, а теперь ему требуется согласие для других областей. В этом случае следует использовать добавочное согласие.
  • Первый API не требует многофакторной проверки подлинности, в отличие от следующего API.
var result = await app.AcquireTokenXX("scopeApi1")
                      .ExecuteAsync();

try
{
 result = await app.AcquireTokenSilent("scopeApi2")
                  .ExecuteAsync();
}
catch(MsalUiRequiredException ex)
{
 result = await app.AcquireTokenInteractive("scopeApi2")
                  .WithClaims(ex.Claims)
                  .ExecuteAsync();
}

Следующие шаги

См. следующую статью для этого сценария: Переход к рабочей среде.