Tutoriel : Connecter des utilisateurs et appeler Microsoft Graph dans une application de bureau Windows Presentation Foundation (WPF)

Dans ce tutoriel, vous allez créer une application Windows Desktop .NET (XAML) native qui connecte des utilisateurs et obtient un jeton d’accès pour appeler l’API Microsoft Graph.

À la fin de ce guide, votre application sera capable d’appeler une API protégée utilisant des comptes personnels (y compris outlook.com, live.com, etc.). L’application utilisera également des comptes professionnels et scolaires de toute entreprise ou organisation utilisant Azure Active Directory.

Dans ce tutoriel, vous allez :

  • Créez un projet Windows Presentation Foundation (WPF) dans Visual Studio
  • Installer la bibliothèque Microsoft Authentication Library (MSAL) pour .NET
  • Inscrire l’application dans le Portail Azure
  • Ajouter du code pour prendre en charge la connexion et la déconnexion des utilisateurs
  • Ajouter du code pour appeler l’API Microsoft Graph
  • Test de l'application

Prérequis

Fonctionnement de l’exemple d’application de ce guide

Shows how the sample app generated by this tutorial works

L’exemple d’application que vous créez avec ce guide permet à une application de bureau Windows d’interroger l’API Microsoft Graph ou une API web qui accepte les jetons d’un point de terminaison de la plateforme d’identité Microsoft. Pour ce scénario, vous ajoutez un jeton aux requêtes HTTP via l’en-tête d’autorisation. La bibliothèque d’authentification Microsoft (MSAL) gère l’acquisition et le renouvellement de jetons.

Gestion de l’acquisition de jetons pour accéder à des API web protégées

Une fois l’utilisateur authentifié, l’exemple d’application reçoit un jeton que vous pouvez utiliser pour interroger l’API Microsoft Graph ou une API web sécurisée par la plateforme d’identité Microsoft.

Les API comme Microsoft Graph nécessitent un jeton d’accès pour autoriser l’accès à des ressources spécifiques. Par exemple, un jeton est nécessaire pour lire le profil d’un utilisateur, accéder au calendrier d’un utilisateur ou envoyer un e-mail. Votre application peut demander un jeton d’accès à l’aide de MSAL pour accéder à ces ressources en spécifiant les étendues d’API. Ce jeton d’accès est ensuite ajouté à l’en-tête d’autorisation HTTP pour chaque appel effectué sur la ressource protégée.

MSAL gère la mise en cache et l’actualisation des jetons d’accès pour vous, ce qui évite à votre application d’avoir à le faire.

Packages NuGet

Ce guide utilise les packages NuGet suivants :

Bibliothèque Description
Microsoft.Identity.Client Bibliothèque d’authentification Microsoft (MSAL.NET)

Configuration de votre projet

Dans cette section, vous allez créer un projet pour apprendre à intégrer une application de bureau Windows .NET (XAML) avec l’option Se connecter avec Microsoft pour que l’application puisse interroger les API web qui nécessitent un jeton.

L’application que vous créez dans ce guide affiche un bouton pour appeler un graphique, une zone pour afficher les résultats à l’écran et un bouton de déconnexion.

Notes

Vous préférez télécharger le projet Visual Studio de cet exemple ? Téléchargez un projet et passez à l’étape Configuration pour configurer l’exemple de code avant de l’exécuter.

Pour créer l’application, procédez comme suit :

  1. Dans Visual Studio, sélectionnez Fichier>Nouveau>Projet.
  2. Sous Modèles, sélectionnez Visual C# .
  3. Sélectionnez Application WPF (.NET Framework) , selon la version Visual Studio que vous utilisez.

Ajouter MSAL à votre projet

  1. Dans Visual Studio, sélectionnez Outils>Gestionnaire de package NuGet>Console du gestionnaire de package.

  2. Dans la fenêtre Console du gestionnaire de package, collez la commande Azure PowerShell suivante :

    Install-Package Microsoft.Identity.Client -Pre
    

    Notes

    Cette commande installe la bibliothèque d’authentification Microsoft. MSAL gère l’acquisition, la mise en cache et l’actualisation des jetons d’utilisateur permettant d’accéder aux API protégées par Azure Active Directory v2.0.

Inscrivez votre application

Vous pouvez inscrire votre application de deux manières.

Option 1 : Mode Express

Vous pouvez inscrire rapidement votre application en procédant comme suit :

  1. Accédez à l’expérience de démarrage rapide Portail Azure - Inscriptions d’applications.
  2. Entrez un nom pour votre application, puis sélectionnez Inscrire.
  3. Suivez les instructions pour télécharger et configurer automatiquement votre nouvelle application en un seul clic.

Option n°2 : Mode Avancé

Pour inscrire votre application et ajouter les informations d’inscription de l’application à votre solution, procédez comme suit :

  1. Connectez-vous au portail Azure.

  2. Si vous avez accès à plusieurs locataires, utilisez le filtre Répertoires + abonnements dans le menu du haut pour basculer vers le locataire dans lequel vous voulez inscrire l’application.

  3. Recherchez et sélectionnez Azure Active Directory.

  4. Sous Gérer, sélectionnez Inscriptions d’applications>Nouvelle inscription.

  5. Entrez un nom pour votre application (par exemple, Win-App-calling-MsGraph). Les utilisateurs de votre application peuvent voir ce nom, et vous pouvez le changer ultérieurement.

  6. Dans la section Types de comptes pris en charge, sélectionnez Comptes dans un annuaire d’organisation (tout annuaire Azure AD - Multilocataire) et comptes Microsoft personnels (par exemple, Skype, Xbox) .

  7. Sélectionnez Inscription.

  8. Sous Gérer, sélectionnez Authentification>Ajouter une plateforme.

  9. Sélectionnez Applications de bureau et mobiles.

  10. Dans la section URI de redirection, sélectionnez https://login.microsoftonline.com/common/oauth2/nativeclient.

  11. Sélectionnez Configurer.

  12. Accédez à Visual Studio, ouvrez le fichier App.xaml.cs, puis remplacez Enter_the_Application_Id_here dans l’extrait de code ci-dessous par l’ID de l’application que vous venez d’inscrire et de copier.

    private static string ClientId = "Enter_the_Application_Id_here";
    

Ajoutez le code pour initialiser MSAL

Dans cette étape, vous allez créer une classe pour gérer l’interaction avec MSAL, telle que la gestion des jetons.

  1. Ouvrez le fichier App.xaml.cs et ajoutez la référence de MSAL à la classe :

    using Microsoft.Identity.Client;
    
  2. Mettez à jour la classe d’application comme suit :

    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 = "0b8b0665-bc13-4fdc-bd72-e0227b9fc011";
    
        private static string Tenant = "common";
    
        private static IPublicClientApplication _clientApp ;
    
        public static IPublicClientApplication PublicClientApp { get { return _clientApp; } }
    }
    

Créer l’interface utilisateur de l’application

La section suivante explique comment une application peut interroger un serveur principal protégé tel que Microsoft Graph.

Un fichier MainWindow.xaml doit être automatiquement créé dans le cadre de votre modèle de projet. Ouvrez ce fichier, puis remplacez le nœud <Grid> de votre application par le code suivant :

<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>

Utiliser MSAL pour obtenir un jeton pour l’API Microsoft Graph

Dans cette section, vous allez utiliser MSAL pour obtenir un jeton pour l’API Microsoft Graph.

  1. Dans le fichier MainWindow.xaml.cs, ajoutez la référence de MSAL à la classe :

    using Microsoft.Identity.Client;
    
  2. Remplacez le code de classe MainWindow par le suivant :

    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;
            }
        }
        }
    

Informations complémentaires

Obtenir un jeton d’utilisateur de manière interactive

L’appel de la méthode AcquireTokenInteractive affiche une fenêtre invitant les utilisateurs à se connecter. Les applications requièrent généralement que les utilisateurs se connectent de manière interactive la première fois qu’ils cherchent à accéder à une ressource protégée. Ils peuvent également avoir besoin de se connecter en cas d’échec d’une opération en mode silencieux pour obtenir un jeton (par exemple, quand un mot de passe utilisateur a expiré).

Obtenir un jeton d’utilisateur en mode silencieux

La méthode AcquireTokenSilent gère les acquisitions et renouvellements de jetons sans aucune interaction de l’utilisateur. Quand AcquireTokenInteractive est exécuté pour la première fois, la méthode AcquireTokenSilent est généralement celle à utiliser pour obtenir les jetons permettant d’accéder aux ressources protégées pour les appels suivants, étant donné que les appels pour les demandes ou renouvellements de jetons se font en mode silencieux.

La méthode AcquireTokenSilent peut échouer. Cet échec peut être dû à une déconnexion de l’utilisateur ou à la modification de son mot de passe sur un autre appareil. Quand la bibliothèque MSAL détecte que le problème peut être résolu par une intervention interactive, elle déclenche une exception MsalUiRequiredException. Votre application peut gérer cette exception de deux manières :

  • Elle peut appeler immédiatement AcquireTokenInteractive. Cet appel invite l’utilisateur à se connecter. Cette méthode est généralement employée dans les applications en ligne où aucun contenu hors connexion n’est disponible pour l’utilisateur. L’exemple généré par cette installation guidée utilise ce modèle, que vous pouvez voir en action la première fois que vous exécutez l’exemple.

  • Aucun utilisateur n’ayant encore utilisé l’application, PublicClientApp.Users.FirstOrDefault() contient une valeur null, et une exception MsalUiRequiredException est levée.

  • Le code de l’exemple gère ensuite cette exception en appelant AcquireTokenInteractive, après quoi l’utilisateur est invité à se connecter.

  • Il peut également afficher à la place une indication visuelle informant les utilisateurs qu’une connexion interactive est nécessaire, pour permettre à ces derniers de sélectionner le bon moment pour se connecter. L’application peut également effectuer une nouvelle tentative de AcquireTokenSilent ultérieurement. Ce modèle est souvent utilisé quand les utilisateurs peuvent utiliser d’autres fonctionnalités de l’application sans interruption, par exemple, quand le contenu hors connexion est disponible dans l’application. Dans ce cas, les utilisateurs peuvent décider de se connecter pour accéder à la ressource protégée ou pour actualiser les informations obsolètes. L’application peut également décider d’effectuer une nouvelle tentative de AcquireTokenSilent une fois le réseau rétabli après une indisponibilité temporaire.

Appeler l’API Microsoft Graph à l’aide du jeton que vous venez d’obtenir

Ajoutez la nouvelle méthode suivante à votre fichier MainWindow.xaml.cs. Cette méthode permet d’envoyer une demande GET à l’API Graph à l’aide d’un en-tête d’autorisation :

/// <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();
    }
}

Informations supplémentaires sur l’envoi d’un appel REST à une API protégée

Dans cet exemple d’application, vous utiliserez la méthode GetHttpContentWithToken pour envoyer une requête HTTP GET à une ressource protégée qui requiert un jeton, puis pour retourner le contenu à l’appelant. Cette méthode ajoute le jeton acquis à l’en-tête d’autorisation HTTP. Dans cet exemple, la ressource est le point de terminaison me de l’API Microsoft Graph, qui affiche les informations de profil de l’utilisateur.

Ajouter une méthode pour déconnecter un utilisateur

Pour déconnecter un utilisateur, ajoutez la méthode suivante à votre fichier 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}";
        }
    }
}

Plus d'informations sur la déconnexion d’utilisateurs

La méthode SignOutButton_Click supprime l’utilisateur du cache utilisateur de MSAL en ordonnant à MSAL d’oublier l’utilisateur actuel pour que la demande suivante d’acquisition de jeton n’aboutisse que si elle est effectuée de manière interactive.

Bien que l’application de cet exemple ne prenne en charge qu’un seul utilisateur, MSAL autorise les scénarios où plusieurs comptes peuvent être connectés en même temps. C’est le cas, par exemple, d’une application de messagerie hébergeant plusieurs comptes d’un même utilisateur.

Afficher les informations de base du jeton

Pour afficher les informations de base du jeton, ajoutez la méthode suivante à votre fichier 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;
    }
}

Informations complémentaires

Outre le jeton d’accès qui est utilisé pour appeler l’API Microsoft Graph, MSAL obtient également un jeton d’ID une fois l’utilisateur connecté. Ce jeton contient un petit sous-ensemble d’informations pertinentes pour les utilisateurs. La méthode DisplayBasicTokenInfo affiche les informations de base du jeton. Par exemple, le nom affiché et l’ID de l’utilisateur, ainsi que la date d’expiration du jeton et la chaîne qui représente le jeton d’accès lui-même. Si vous cliquez plusieurs fois sur le bouton Call Microsoft Graph API (Appeler l’API Microsoft Graph), vous observerez que le même jeton a été réutilisé pour les demandes suivantes. Vous constatez également que la date d’expiration est différée lorsque MSAL détermine qu’il est temps de renouveler le jeton.

Test de votre code

Pour exécuter votre projet, sélectionnez F5 dans Visual Studio. Votre application MainWindow s’affiche, comme illustré ici :

Test your application

La première fois que vous exécutez l’application et que vous sélectionnez le bouton Call Microsoft Graph API (Appeler l’API Microsoft Graph), vous êtes invité à vous connecter. Utilisez un compte Azure Active Directory (compte professionnel ou scolaire) ou un compte Microsoft (live.com, outlook.com) pour tester votre application.

Sign in to the application

La première fois que vous vous connectez à votre application, vous êtes également invité à autoriser l’application à accéder à votre profil et vous connecter, comme illustré ici :

Provide your consent for application access

Afficher les résultats de l’application

Une fois connecté, vous devez voir les informations de profil utilisateur qui sont retournées par l’appel à l’API Microsoft Graph. Les résultats s’affichent dans la zone API Call Results (Résultats de l’appel à l’API). Les informations de base concernant le jeton qui a été acquis via l’appel à AcquireTokenInteractive ou AcquireTokenSilent doivent s’afficher dans la zone Token Info (Informations sur le jeton). Les résultats contiennent les propriétés suivantes :

Propriété Format Description
Nom d’utilisateur user@domain.com Nom d’utilisateur employé pour identifier l’utilisateur.
Token Expires DateTime Date et heure auxquelles expire le jeton. MSAL repousse la date d’expiration en renouvelant le jeton si nécessaire.

Informations supplémentaires sur les étendues et les autorisations déléguées

L’API Microsoft Graph nécessite l’étendue user.read pour lire le profil d’un utilisateur. Par défaut, cette étendue est automatiquement ajoutée à toutes les applications inscrites dans le portail d’inscription de l’application. D’autres API pour Microsoft Graph ainsi que des API personnalisées pour votre serveur principal peuvent nécessiter des étendues supplémentaires. L’API Microsoft Graph nécessite l’étendue Calendars.Read pour lister les calendriers de l’utilisateur.

Pour accéder aux calendriers de l’utilisateur dans le contexte d’une application, ajoutez l’autorisation déléguée Calendars.Read aux informations d’inscription de l’application. Ajoutez ensuite l’étendue Calendars.Read à l’appel acquireTokenSilent.

Notes

L’utilisateur peut être invité à donner des consentements supplémentaires à mesure que vous augmentez le nombre d’étendues.

Aide et support

Si vous avez besoin d’aide, si vous souhaitez signaler un problème ou si vous voulez en savoir plus sur vos options de support, consultez Aide et support pour les développeurs.

Étapes suivantes

En savoir plus sur la création d’applications de bureau qui appellent des API Web protégées dans notre série de scénarios en plusieurs parties :