Получение маркера для мобильного приложения, вызывающего веб-API

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

Определение области

При запросе маркера определите область. Область определяет, к каким данным приложение имеет доступ.

Самый простой способ определить область — объединить нужные веб-API App ID URI с областью .default. Это определение указывает платформе удостоверений Майкрософт, что приложению требуются все области, заданные на портале.

Android

String[] SCOPES = {"https://graph.microsoft.com/.default"};

iOS

let scopes = ["https://graph.microsoft.com/.default"]

Xamarin

var scopes = new [] {"https://graph.microsoft.com/.default"};

Получение маркеров

Получение маркеров через MSAL

MSAL позволяет приложениям получать маркеры автоматически и интерактивно. При вызове метода AcquireTokenSilent() или AcquireTokenInteractive() MSAL возвращает маркер доступа для запрошенных областей. Правильный порядок действий заключается в том, чтобы выполнить автоматический запрос, а затем вернуться к интерактивному запросу.

Android

String[] SCOPES = {"https://graph.microsoft.com/.default"};
PublicClientApplication sampleApp = new PublicClientApplication(
                    this.getApplicationContext(),
                    R.raw.auth_config);

// Check if there are any accounts we can sign in silently.
// Result is in the silent callback (success or error).
sampleApp.getAccounts(new PublicClientApplication.AccountsLoadedCallback() {
    @Override
    public void onAccountsLoaded(final List<IAccount> accounts) {

        if (accounts.isEmpty() && accounts.size() == 1) {
            // TODO: Create a silent callback to catch successful or failed request.
            sampleApp.acquireTokenSilentAsync(SCOPES, accounts.get(0), getAuthSilentCallback());
        } else {
            /* No accounts or > 1 account. */
        }
    }
});

[...]

// No accounts found. Interactively request a token.
// TODO: Create an interactive callback to catch successful or failed requests.
sampleApp.acquireToken(getActivity(), SCOPES, getAuthInteractiveCallback());

iOS

Сначала попытайтесь получить маркер автоматически:


NSArray *scopes = @[@"https://graph.microsoft.com/.default"];
NSString *accountIdentifier = @"my.account.id";

MSALAccount *account = [application accountForIdentifier:accountIdentifier error:nil];

MSALSilentTokenParameters *silentParams = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:account];
[application acquireTokenSilentWithParameters:silentParams completionBlock:^(MSALResult *result, NSError *error) {

    if (!error)
    {
        // You'll want to get the account identifier to retrieve and reuse the account
        // for later acquireToken calls
        NSString *accountIdentifier = result.account.identifier;

        // Access token to call the web API
        NSString *accessToken = result.accessToken;
    }

    // Check the error
    if (error && [error.domain isEqual:MSALErrorDomain] && error.code == MSALErrorInteractionRequired)
    {
        // Interactive auth will be required, call acquireTokenWithParameters:error:
        return;
    }
}];

let scopes = ["https://graph.microsoft.com/.default"]
let accountIdentifier = "my.account.id"

guard let account = try? application.account(forIdentifier: accountIdentifier) else { return }
let silentParameters = MSALSilentTokenParameters(scopes: scopes, account: account)
application.acquireTokenSilent(with: silentParameters) { (result, error) in

    guard let authResult = result, error == nil else {

    let nsError = error! as NSError

    if (nsError.domain == MSALErrorDomain &&
        nsError.code == MSALError.interactionRequired.rawValue) {

            // Interactive auth will be required, call acquireToken()
            return
         }
         return
     }

    // You'll want to get the account identifier to retrieve and reuse the account
    // for later acquireToken calls
    let accountIdentifier = authResult.account.identifier

    // Access token to call the web API
    let accessToken = authResult.accessToken
}

Если MSAL возвращает MSALErrorInteractionRequired, попробуйте получить маркеры в интерактивном режиме:

UIViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively
MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController];
MSALInteractiveTokenParameters *interactiveParams = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes webviewParameters:webParameters];
[application acquireTokenWithParameters:interactiveParams completionBlock:^(MSALResult *result, NSError *error) {
    if (!error)
    {
        // You'll want to get the account identifier to retrieve and reuse the account
        // for later acquireToken calls
        NSString *accountIdentifier = result.account.identifier;

        NSString *accessToken = result.accessToken;
    }
}];
let viewController = ... // Pass a reference to the view controller that should be used when getting a token interactively
let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController)
let interactiveParameters = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webviewParameters)
application.acquireToken(with: interactiveParameters, completionBlock: { (result, error) in

    guard let authResult = result, error == nil else {
        print(error!.localizedDescription)
        return
    }

    // Get access token from result
    let accessToken = authResult.accessToken
})

MSAL для iOS и macOS поддерживает различные модификаторы для интерактивного или автоматического получения маркера:

Xamarin

В следующем примере приведен минимальный код для интерактивного получения маркера. В этом примере для чтения профиля пользователя используется Microsoft Graph.

string[] scopes = new string[] {"user.read"};
var app = PublicClientApplicationBuilder.Create(clientId).Build();
var accounts = await app.GetAccountsAsync();
AuthenticationResult result;
try
{
 result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
             .ExecuteAsync();
}
catch(MsalUiRequiredException)
{
 result = await app.AcquireTokenInteractive(scopes)
             .ExecuteAsync();
}

Обязательные параметры в MSAL.NET

AcquireTokenInteractive имеет один обязательный параметр — scopes. Параметр scopes перечисляет строки, определяющие области, для которых требуется маркер. Если маркер предназначен для Microsoft Graph, необходимые области можно найти в справочнике по API каждого Microsoft Graph API. В справочнике они указаны в разделе "Разрешения".

Например, для списка контактов пользователя необходимо использовать область "User.Read", "Contacts.Read". См. сведения о разрешениях Microsoft Graph.

При создании приложения в Android можно указать родительское действие с помощью PublicClientApplicationBuilder. Если вы не укажете родительские действия в это время, его можно будет указать позже с помощью команды .WithParentActivityOrWindow, как показано в следующем разделе. Если родительское действие указано, маркер будет возвращен родительскому действию после взаимодействия. Если оно не указано .ExecuteAsync(), вызов создает исключение.

Определенные необязательные параметры в MSAL.NET

В следующих разделах описываются необязательные параметры в MSAL.NET.

WithPrompt

Параметр WithPrompt() используется для управления интерактивным взаимодействием с пользователем путем указания запроса.

Image showing the fields in the Prompt structure. These constant values control interactivity with the user by defining the type of prompt displayed by the WithPrompt() parameter.

Класс определяет следующие константы:

  • SelectAccount указывает службе маркеров безопасности (STS) представлять диалоговое окно выбора учетной записи. Это диалоговое окно содержит учетные записи, для которых у пользователя есть сеанс. Этот параметр можно использовать, если вы хотите разрешить пользователю выбирать между разными удостоверениями. Этот параметр позволяет MSAL отправлять prompt=select_account поставщику удостоверений.

    Константа SelectAccount используется по умолчанию и эффективно обеспечивает оптимальное взаимодействие на основе доступной информации. К доступной информации может относиться учетная запись, присутствие сеанса для пользователя и т. д. Не изменяйте это значение по умолчанию, если у вас нет веских причин.

  • Consent позволяет запрашивать согласие пользователя, даже если оно уже было предоставлено. В этом случае MSAL отправляет prompt=consent поставщику удостоверений.

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

  • ForceLogin позволяет службе предлагать пользователю ввести учетные данные, даже если такой запрос не требуется.

    Этот вариант может быть полезен, когда нужно позволить пользователю снова войти в систему при сбое получения маркера. В этом случае MSAL отправляет prompt=login поставщику удостоверений. Этот вариант можно использовать в приложениях, ориентированных на безопасность, где управление организацией требует, чтобы пользователь повторно выполнял вход при каждом обращении к конкретным частям приложения.

  • Never предназначен только для .NET 4,5 и среды выполнения Windows (WinRT). Эта константа не запрашивает пользователя, а вместо этого пытается использовать файл cookie, хранящийся в скрытом внедренном веб-представлении. Дополнительные сведения см. в статье Использование веб-браузеров с MSAL.NET.

    Если при использовании этого варианта возникает сбой, AcquireTokenInteractive создает исключение, чтобы уведомить о необходимости взаимодействия с пользовательским интерфейсом. Тогда используйте другой параметр Prompt.

  • NoPrompt не отправляет запрос поставщику удостоверений.

    Этот параметр полезен только для политик изменения профилей в Azure Active Directory B2C. Дополнительные сведения см. в разделе об особенностях B2C.

WithExtraScopeToConsent

Используйте модификатор WithExtraScopeToConsent в расширенном сценарии, где пользователь должен заранее согласиться на несколько ресурсов. Этот модификатор можно применять, если вы не хотите использовать добавочное согласие, которое обычно используется с платформой удостоверений Microsoft или MSAL.NET. Дополнительные сведения см. в разделе Получение согласия пользователя на несколько ресурсов заранее.

Ниже приведен пример кода:

var result = await app.AcquireTokenInteractive(scopesForCustomerApi)
                     .WithExtraScopeToConsent(scopesForVendorApi)
                     .ExecuteAsync();
Другие необязательные параметры

Дополнительные сведения о других необязательных параметрах для AcquireTokenInteractive см. в справочной документации по AcquireTokenInteractiveParameterBuilder.

Получение маркеров через протокол

Мы не рекомендуем напрямую использовать протокол для получения маркеров. Если это сделать, приложение не будет поддерживать некоторые сценарии, включающие единый вход (SSO), управление устройствами и условный доступ.

При использовании протокола для получения маркеров для мобильных приложений выполните два запроса:

  • Получение кода авторизации.
  • Обмен кода на маркер.

Получение коде авторизации.

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=<CLIENT_ID>
&response_type=code
&redirect_uri=<ENCODED_REDIRECT_URI>
&response_mode=query
&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2F.default
&state=12345

Получение доступа и обновление токена

POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

client_id=<CLIENT_ID>
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr...
&redirect_uri=<ENCODED_REDIRECT_URI>
&grant_type=authorization_code

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

Перейдите к следующей статье в этом сценарии, Вызов веб-API.