Поделиться через


Руководство по входу пользователей и вызову Microsoft Graph в классическом приложении Windows Presentation Foundation (WPF)

Область применения: Зеленый круг с символом белой галочки. арендаторы рабочей силы Зеленый круг с символом белой галочки. внешние арендаторы (узнать больше)

В этом руководстве показано, как создать нативное классическое приложение Windows .NET (XAML), которое поддерживает вход пользователей и может получить маркер доступа для вызова API Microsoft Graph.

После выполнения руководства ваше приложение сможет вызвать защищенный API, использующий личные учетные записи (включая outlook.com, live.com и другие). Приложение также будет использовать рабочие и учебные учетные записи из любой компании или организации, которая использует идентификатор Microsoft Entra.

Изучив это руководство, вы:

  • создание проекта Windows Presentation Foundation (WPF) в Visual Studio;
  • установка библиотеки аутентификации Майкрософт (MSAL) для .NET;
  • Регистрация приложения
  • добавление кода для поддержки входа и выхода пользователей;
  • добавление кода для вызова API Microsoft Graph;
  • Тестирование приложения

Предварительные условия

  • Арендатор рабочей силы. Вы можете использовать каталог по умолчанию или настроить нового арендатора.
  • Зарегистрируйте новое приложение в Центре администрирования Microsoft Entra, настроенное для учетных записей в любом каталоге организации и личных учетных записях Майкрософт. Дополнительные сведения см. в статье "Регистрация приложения ". Запишите следующие значения на странице обзора приложения для последующего использования:
    • Идентификатор приложения (клиента)
    • Идентификатор каталога (арендатора)
  • Добавьте следующие URI перенаправления, используя конфигурацию платформы для мобильных и настольных приложений. Дополнительные сведения см. в статье о добавлении URI перенаправления в приложение .
    • Переадресация URI: https://login.microsoftonline.com/common/oauth2/nativeclient
  • .NET Framework 4.8
  • Visual Studio 2019

Как работает пример приложения, созданный в этом руководстве

Снимок экрана: способ работы примера приложения, созданного этим руководством.

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

Обработка получения токена для доступа к защищенным веб-API

После аутентификации пользователя образец приложения получает токен, который можно использовать для выполнения запросов к API Microsoft Graph или веб-API, защищенному платформой идентификации Microsoft.

Программным интерфейсам, таким как Microsoft Graph, для доступа к определенным ресурсам требуется маркер. Например, маркер требуется для чтения профиля пользователя, доступа к календарю пользователя или отправки электронной почты. Приложение может запросить маркер доступа с помощью MSAL, чтобы получить доступ к этим ресурсам, указав определенные области API. Затем этот маркер доступа добавляется в заголовок авторизации HTTP для каждого вызова к защищенному ресурсу.

MSAL управляет кэшированием и обновлением маркеров доступа, поэтому вашему приложению не нужно этого делать.

Пакеты NuGet

В этом руководстве используются следующие пакеты NuGet:

Библиотека Описание
Microsoft.Identity.Client Библиотека аутентификации Майкрософт (MSAL)

Настройка проекта

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

Создаваемое приложение отображает кнопку, которая вызовет API Microsoft Graph, область для отображения результатов и кнопку выхода.

Примечание.

Предпочитаете ли вы вместо этого скачать пример проекта Visual Studio? Скачайте проект и зарегистрируйте приложение, чтобы настроить пример кода перед его выполнением.

Создайте приложение, выполнив следующие действия:

  1. Запустите Visual Studio
  2. В окне запуска выберите Создание нового проекта.
  3. В раскрывающемся списке "Все языки " выберите C#.
  4. Найдите и выберите шаблон приложения WPF (платформа .NET Framework), а затем нажмите кнопку "Далее".
  5. В поле "Имя проекта" введите имя, например Win-App-calling-MsGraph.
  6. Выберите расположение проекта или примите параметр по умолчанию.
  7. В Framework выберите .NET Framework 4.8.
  8. Нажмите кнопку создания.

Добавление MSAL в проект

  1. В Visual Studio выберите Сервис>Диспетчер пакетов NuGet>Консоль диспетчера пакетов.

  2. В окне консоли диспетчера пакетов вставьте следующую команду Azure PowerShell:

    Install-Package Microsoft.Identity.Client -Pre
    

Добавление кода для инициализации MSAL

На этом шаге вы создадите класс для обработки взаимодействия с MSAL, например обработки маркеров.

  1. Откройте файл App.xaml.cs, а затем добавьте ссылку для MSAL в класс:

    using Microsoft.Identity.Client;
    
  2. Обновите класс app следующим образом:

    public partial class App : Application
    {
        static App()
        {
            _clientApp = PublicClientApplicationBuilder.Create(ClientId)
                .WithAuthority(AzureCloudInstance.AzurePublic, Tenant)
                .WithDefaultRedirectUri()
                .Build();
        }
    
        // Below are the clientId (Application Id) of your app registration and the tenant information.
        // You have to replace:
        // - the content of ClientID with the Application Id for your app registration
        // - the content of Tenant by the information about the accounts allowed to sign-in in your application:
        //   - For Work or School account in your org, use your tenant ID, or domain
        //   - for any Work or School accounts, use `organizations`
        //   - for any Work or School accounts, or Microsoft personal account, use `common`
        //   - for Microsoft Personal account, use consumers
        private static string ClientId = "Enter_the_Application_Id_here";
    
        private static string Tenant = "common";
    
        private static IPublicClientApplication _clientApp ;
    
        public static IPublicClientApplication PublicClientApp { get { return _clientApp; } }
    }
    

Создание пользовательского интерфейса приложения

В этом разделе описывается, как приложение может запрашивать защищенный внутренний сервер, например Microsoft Graph.

Файл MainWindow.xaml автоматически создается в рамках шаблона проекта. Откройте этот файл и замените узел <Сетка> в коде вашего приложения следующим:

<Grid>
    <StackPanel Background="Azure">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <Button x:Name="CallGraphButton" Content="Call Microsoft Graph API" HorizontalAlignment="Right" Padding="5" Click="CallGraphButton_Click" Margin="5" FontFamily="Segoe Ui"/>
            <Button x:Name="SignOutButton" Content="Sign-Out" HorizontalAlignment="Right" Padding="5" Click="SignOutButton_Click" Margin="5" Visibility="Collapsed" FontFamily="Segoe Ui"/>
        </StackPanel>
        <Label Content="API Call Results" Margin="0,0,0,-5" FontFamily="Segoe Ui" />
        <TextBox x:Name="ResultText" TextWrapping="Wrap" MinHeight="120" Margin="5" FontFamily="Segoe Ui"/>
        <Label Content="Token Info" Margin="0,0,0,-5" FontFamily="Segoe Ui" />
        <TextBox x:Name="TokenInfoText" TextWrapping="Wrap" MinHeight="70" Margin="5" FontFamily="Segoe Ui"/>
    </StackPanel>
</Grid>

Используйте MSAL для получения токена для API Microsoft Graph

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

  1. В файле MainWindow.xaml.cs добавьте ссылку для MSAL в класс:

    using Microsoft.Identity.Client;
    
  2. Замените MainWindow код класса следующим кодом:

    public partial class MainWindow : Window
    {
        //Set the API Endpoint to Graph 'me' endpoint
        string graphAPIEndpoint = "https://graph.microsoft.com/v1.0/me";
    
        //Set the scope for API call to user.read
        string[] scopes = new string[] { "user.read" };
    
    
        public MainWindow()
        {
            InitializeComponent();
        }
    
      /// <summary>
        /// Call AcquireToken - to acquire a token requiring user to sign-in
        /// </summary>
        private async void CallGraphButton_Click(object sender, RoutedEventArgs e)
        {
            AuthenticationResult authResult = null;
            var app = App.PublicClientApp;
            ResultText.Text = string.Empty;
            TokenInfoText.Text = string.Empty;
    
            var accounts = await app.GetAccountsAsync();
            var firstAccount = accounts.FirstOrDefault();
    
            try
            {
                authResult = await app.AcquireTokenSilent(scopes, firstAccount)
                    .ExecuteAsync();
            }
            catch (MsalUiRequiredException ex)
            {
                // A MsalUiRequiredException happened on AcquireTokenSilent.
                // This indicates you need to call AcquireTokenInteractive to acquire a token
                System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
    
                try
                {
                    authResult = await app.AcquireTokenInteractive(scopes)
                        .WithAccount(accounts.FirstOrDefault())
                        .WithPrompt(Prompt.SelectAccount)
                        .ExecuteAsync();
                }
                catch (MsalException msalex)
                {
                    ResultText.Text = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
                }
            }
            catch (Exception ex)
            {
                ResultText.Text = $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}";
                return;
            }
    
            if (authResult != null)
            {
                ResultText.Text = await GetHttpContentWithToken(graphAPIEndpoint, authResult.AccessToken);
                DisplayBasicTokenInfo(authResult);
                this.SignOutButton.Visibility = Visibility.Visible;
            }
        }
        }
    

Дополнительные сведения

Интерактивное получение пользовательского токена

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

Без участия пользователя получение токена клиента

Метод AcquireTokenSilent обрабатывает получение и обновление токенов без какого-либо участия пользователя. После первого выполнения метода AcquireTokenInteractive обычно используется метод AcquireTokenSilent, чтобы получить токены для доступа к защищенным ресурсам для последующих вызовов, так как вызовы для запроса или обновления токенов выполняются в фоновом режиме.

Метод AcquireTokenSilent в какой-то момент может завершиться ошибкой. Причина может заключаться в том, что пользователь вышел из системы или изменил пароль на другом устройстве. Когда MSAL обнаруживает, что эту проблему можно решить, запросив интерактивное действие, возникает исключение MsalUiRequiredException. Приложение может обработать это исключение двумя способами:

  • Может немедленно совершить вызов для AcquireTokenInteractive. Этот вызов приводит к предложению пользователю войти в систему. Этот шаблон используется в онлайн-приложениях, где нет доступного автономного содержимого для пользователя. Пример, созданный этой настройкой, следует этому шаблону, который можно увидеть в действии при первом выполнении примера.

  • Так как приложение еще не использовалось, PublicClientApp.Users.FirstOrDefault() будет содержать значение NULL и будет выдано исключение MsalUiRequiredException.

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

  • Также приложение может визуально уведомить пользователей, что требуется интерактивный вход, чтобы они могли выбрать подходящее время для входа. Либо приложение может попытаться повторно выполнить метод AcquireTokenSilent позже. Этот шаблон часто используется, когда пользователи могут использовать другие функциональные возможности приложений без нарушений. Например, когда автономное содержимое доступно в приложении. В этом случае пользователи могут решать, что им нужно сделать после входа — получить доступ к защищенному ресурсу или обновить устаревшие данные. Кроме того, приложение может попытаться повторно выполнить AcquireTokenSilent при восстановлении сети после временной недоступности.

Вызовите API Microsoft Graph, используя только что полученный токен.

Добавьте в MainWindow.xaml.cs следующий новый метод. Этот метод используется для выполнения запроса GET к Graph API с помощью заголовка "Авторизация".

/// <summary>
/// Perform an HTTP GET request to a URL using an HTTP Authorization header
/// </summary>
/// <param name="url">The URL</param>
/// <param name="token">The token</param>
/// <returns>String containing the results of the GET operation</returns>
public async Task<string> GetHttpContentWithToken(string url, string token)
{
    var httpClient = new System.Net.Http.HttpClient();
    System.Net.Http.HttpResponseMessage response;
    try
    {
        var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
        //Add the token in Authorization header
        request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
        response = await httpClient.SendAsync(request);
        var content = await response.Content.ReadAsStringAsync();
        return content;
    }
    catch (Exception ex)
    {
        return ex.ToString();
    }
}

Дополнительные сведения о вызове REST через защищенный API

В этом примере приложения вы используете метод GetHttpContentWithToken для выполнения HTTP-запроса GET к защищенному ресурсу, требующему токен, и возврата содержимого вызывающей стороне. Этот метод добавляет полученный маркер в заголовок авторизации HTTP. В этом примере ресурс — это конечная точка me API Microsoft Graph, которая отображает сведения о профиле пользователя.

Добавить метод для выхода пользователя

Чтобы выйти из учетной записи пользователя, добавьте следующий метод в файл MainWindow.xaml.cs:

/// <summary>
/// Sign out the current user
/// </summary>
private async void SignOutButton_Click(object sender, RoutedEventArgs e)
{
    var accounts = await App.PublicClientApp.GetAccountsAsync();

    if (accounts.Any())
    {
        try
        {
            await App.PublicClientApp.RemoveAsync(accounts.FirstOrDefault());
            this.ResultText.Text = "User has signed-out";
            this.CallGraphButton.Visibility = Visibility.Visible;
            this.SignOutButton.Visibility = Visibility.Collapsed;
        }
        catch (MsalException ex)
        {
            ResultText.Text = $"Error signing-out user: {ex.Message}";
        }
    }
}

Дополнительные сведения о выходе пользователя

Метод SignOutButton_Click удаляет пользователей из пользовательского кеша MSAL, что фактически заставляет MSAL забыть текущего пользователя, так что будущий запрос на получение токена происходит только при интерактивном взаимодействии.

Хотя приложение в этом примере поддерживает одного пользователя, MSAL поддерживает сценарии, в которых несколько пользователей могут войти в систему одновременно. Пример — приложение электронной почты, в котором у пользователя есть несколько учетных записей.

Отображение основных сведений о токене

Для отображения основных сведений о токене добавьте следующий метод в файл MainWindow.xaml.cs:

/// <summary>
/// Display basic information contained in the token
/// </summary>
private void DisplayBasicTokenInfo(AuthenticationResult authResult)
{
    TokenInfoText.Text = "";
    if (authResult != null)
    {
        TokenInfoText.Text += $"Username: {authResult.Account.Username}" + Environment.NewLine;
        TokenInfoText.Text += $"Token Expires: {authResult.ExpiresOn.ToLocalTime()}" + Environment.NewLine;
    }
}

Дополнительные сведения

После того как пользователь войдет в систему, MSAL также получает токен идентификации в дополнение к токену доступа, который используется для вызова Microsoft Graph API. Этот маркер содержит небольшое подмножество сведений, относящихся к пользователям. Метод DisplayBasicTokenInfo отображает основные сведения, содержащиеся в токене. Например, он показывает отображаемое имя и идентификатор пользователя, а также дату истечения срока действия маркера и строку, представляющую сам маркер доступа. Нажав кнопку вызова API Microsoft Graph несколько раз, вы увидите, что для последующих запросов повторно используется тот же маркер. Вы также можете увидеть продление срока действия, когда MSAL решает, что пришло время обновить токен.

Тестирование кода

Чтобы запустить проект в Visual Studio, нажмите клавишу F5. Отображается приложение MainWindow .

При первом запуске приложения и нажатии кнопки Call Microsoft Graph API (Вызов API Graph Microsoft) появится запрос на вход. Используйте учетную запись Microsoft Entra (рабочую или учебную учетную запись) или учетную запись Майкрософт (live.com, outlook.com), чтобы протестировать ее.

Выполните вход в приложение.

Войдя в приложение первый раз, необходимо будет предоставить ему разрешение на использование данных вашего профиля для входа, как показано ниже:

Предоставьте согласие на доступ к приложению.

Просмотр результатов приложения

После входа вы увидите сведения о профиле пользователя, возвращаемую вызовом API Microsoft Graph. Результаты отображаются в поле API Call Results (Результаты вызова API). Основные сведения о токене, полученном при вызове AcquireTokenInteractive или AcquireTokenSilent, должны отображаться в поле Token Info (Сведения о токене). Результаты содержат следующие свойства:

Свойство Формат Описание
Имя пользователя [email protected] Имя пользователя, которое используется для идентификации пользователя.
Истечение срока действия токена Дата/время Время истечения срока действия токена. MSAL продлевает срок действия, по мере необходимости обновляя маркер.

Дополнительные сведения об областях и делегированных разрешениях

Для чтения профиля пользователя API Microsoft Graph требуется область user.read. По умолчанию эта область автоматически добавляется в каждое приложение, зарегистрированное на портале регистрации приложений. Другие API для Microsoft Graph и пользовательские API для серверного сервера могут требовать больше областей. Для отображения списка календарей пользователя API Microsoft Graph требуется область Calendars.Read.

Чтобы из контекста приложения получить доступ к календарям пользователя, добавьте делегированное разрешение Calendars.Read в сведения о регистрации приложения. Затем добавьте область Calendars.Read в вызов acquireTokenSilent.

Примечание.

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

Справка и поддержка

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

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

Узнайте больше о создании настольных приложений, вызывающих защищенные веб-API, в нашей многосерийной серии сценариев.