Démarrage rapide : enregistrez et configurez une application SPA pour Dataverse en utilisant msal.js

Cette rubrique décrit le processus d’enregistrement et de configuration de l’application sur une seule page (SPA) la plus simple pour accéder aux données dans Microsoft Dataverse à l’aide de msal.js et du partage des ressources cross-origin (CORS). Pour plus d’informations, voir : Utiliser OAuth avec le partage des ressources cross-origin pour connecter une application monopage à Dataverse .

Conditions préalables

Objectif de ce démarrage rapide

À la fin de ce démarrage rapide, vous serez en mesure d’exécuter une application SPA simple, ce qui permettra à un utilisateur de s’authentifier et de récupérer des données de Dataverse.

Lorsque vous déboguez initialement l’application, seul un bouton Se connecter s’affiche.

  • Cliquez sur Connexion et une fenêtre contextuelle s’ouvrira pour entrer vos informations d’identification.

  • Après avoir entré vos informations d’identification, vous verrez que le bouton Se connecter est masqué et un bouton Se déconnecter et un bouton Obtenir les comptes sont visibles. Vous verrez également un message de bienvenue contenant des informations sur votre compte d’utilisateur.

  • Cliquez sur le bouton Obtenir les comptes pour récupérer 10 enregistrements de compte de votre organisation Dataverse. La capture d’écran suivante présente le résultat :

    Page SimpleSPA.

  • Enfin, vous pouvez cliquer sur le bouton Se déconnecter pour vous déconnecter.

Notes

Cette application SPA n’est pas conçue pour représenter un modèle de développement d’applications SPA robustes. Elle est simplifiée pour se concentrer sur le processus d’enregistrement et de configuration de l’application.

Obtenir votre point de terminaison d’API web Dataverse

Utilisez les instructions dans Afficher les ressources pour les développeurs pour identifier un point de terminaison d’API web pour un environnement auquel vous pouvez accéder. La syntaxe devrait être similaire à ceci : https://yourorg.api.crm.dynamics.com/api/data/v9.2.

Enregistrer votre application

  1. Dans le Centre d’administration Power Platform, dans le volet de navigation de gauche, développez Centres d’administration et sélectionnez Microsoft Entra ID.

    Microsoft Entra ID à partir du centre d’administration Power Platform

    Cela ouvre le Centre d’administration Microsoft Entra

  2. Développez Applications et sélectionnez Inscriptions d’applications.

    Enregistrements d’applications Azure depuis le centre d’administration Microsoft Entra

  3. Cliquez sur Nouvelle inscription. Cela ouvrira le formulaire Enregistrer une application.

    Enregistrer un formulaire d’application

  4. Dans le formulaire Enregistrer une application, entrez Nom. Pour les besoins de ce guide de démarrage rapide, utilisez le nom SPA simple.

  5. Pour Types de compte pris en charge, la sélection par défaut doit être :
    Comptes dans cet annuaire d’organisation uniquement (<nom du client> uniquement – Locataire unique). Ne modifiez pas cette valeur.

  6. Pour URI de redirection (facultatif), utilisez ces options :

    • Sélectionner une plateforme : Application monopage (SPA)
    • e.g. https://example.com/auth : http://localhost:5500/index.html
  7. Cliquez sur S’inscrire.

  8. Dans la zone Vue d’ensemble, copiez les valeurs suivantes, car vous en aurez besoin à l’étape finale de Créer un projet d’application web.

    • ID d’application (client)
    • ID du répertoire (locataire)
  9. Sélectionnez Autorisations API.

  10. Cliquez sur Ajouter une autorisation.

  11. Dans le menu volant Demander des autorisations API, sélectionnez Dynamics CRM.

    • Si Dynamics CRM ne s’affiche pas, recherchez Dataverse. Sinon, choisissez l’onglet API utilisées par mon organisation et recherchez Dataverse.
  12. Sélectionnez l’autorisation déléguée user_impersonation.

  13. Cliquez sur Ajouter des autorisations.

Les autorisations configurées doivent ressembler à ceci quand vous avez terminé :

Autorisations configurées pour l’application Simple SPA

Installer l’extension Live Server de Visual Studio Code

Live Server est une extension de Visual Studio Code qui vous permet de lancer facilement un serveur de développement local pour les pages web.

  1. Utilisez ces instructions pour trouver et installer l’extension Live Server pour VS Code sur la marketplace VS Code :

  2. Après avoir installé l’extension Live Server, apportez ces modifications aux paramètres par défaut.

  3. Cliquez sur l’icône d’engrenage dans VS Code et sélectionnez Paramètres, ou utilisez le raccourci clavier Ctrl+,.

  4. Dans la fenêtre de recherche, tapez liveServer.settings.host et modifiez la valeur par défaut de 127.0.0.1 à localhost.

Créer un projet d’application Web

  1. Créez un dossier sur votre ordinateur. Le nom n’est pas important, mais pour les besoins de ces instructions, nommez-le simplespa.

  2. Ouvrez VS Code, puis sélectionnez Fichier > Ouvrir le dossier dans le menu. Sélectionnez le dossier simplespa.

  3. Créez un fichier HTML dans le dossier nommé index.html. (Pas index.htm)

  4. Copiez le contenu ci-dessous dans le fichier index.html :

    <html>
     <head>
       <meta charset="UTF-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <script>
          const baseUrl = "https://org.api.crm.dynamics.com";      //<= Change this
          const clientId = "11111111-1111-1111-1111-111111111111"; //<= Change this
          const tenantId = "22222222-2222-2222-2222-222222222222"; //<= Change this
          const redirectUrl = "http://localhost:5500/index.html";
          const webAPIEndpoint = baseUrl +"/api/data/v9.2";
    
    
          // Configuration object to be passed to MSAL instance on creation. 
    
          const msalConfig = {
             auth: {       
                clientId: clientId,
                // Full directory URL, in the form of https://login.microsoftonline.com/<tenant-id>
                authority: "https://login.microsoftonline.com/"+tenantId,       
                redirectUri: redirectUrl,
             },
             cache: {
                cacheLocation: "sessionStorage" // This configures where your cache will be stored
             },
             system: {   
                loggerOptions: {   
                   loggerCallback: (level, message, containsPii) => {   
                         if (containsPii) {      
                            return;      
                         }      
                         switch (level) {      
                            case msal.LogLevel.Error:      
                               console.error(message);      
                               return;      
                            case msal.LogLevel.Info:      
                               console.info(message);      
                               return;      
                            case msal.LogLevel.Verbose:      
                               console.debug(message);      
                               return;      
                            case msal.LogLevel.Warning:      
                               console.warn(message);      
                               return;      
                         }   
                   }   
                }   
             }
          };
    
       </script>
          <!-- Latest version of msal-browser.js from CDN as of 2022/09 -->
       <script
             type="text/javascript" 
             src="https://alcdn.msauth.net/browser/2.28.1/js/msal-browser.min.js">
       </script>
       <style>
          body {  
             font-family: 'Segoe UI';  
          }  
    
          table {  
             border-collapse: collapse;  
          }  
    
          td, th {  
             border: 1px solid black;  
          }
    
          #message {  
             color: green;  
          }
    </style>
    </head>
    <body>
    <div>
       <button id="loginButton" onclick="signIn()">Login</button>
       <button id="logoutButton" onclick="signOut()" style="display:none;">Logout</button>
       <button id="getAccountsButton" onclick="getAccounts(writeTable)" style="display:none;">Get Accounts</button>  
       <div id="message"></div>
       <table id="accountsTable" style="display:none;">  
        <thead><tr><th>Name</th><th>City</th></tr></thead>  
        <tbody id="accountsTableBody"></tbody>  
       </table>
    </div>
    <script>
       const loginButton = document.getElementById("loginButton");
       const logoutButton = document.getElementById("logoutButton");
       const getAccountsButton = document.getElementById("getAccountsButton");
       const accountsTable = document.getElementById("accountsTable");
       const accountsTableBody = document.getElementById("accountsTableBody");
       const message = document.getElementById("message");
       // Create the main myMSALObj instance
       const myMSALObj = new msal.PublicClientApplication(msalConfig);
    
       let username = "";
    
       // Sets the username. Called at the end of this script.
       function selectAccount() {
    
          const currentAccounts = myMSALObj.getAllAccounts();
          if (currentAccounts.length === 0) {
             return;
          } else if (currentAccounts.length > 1) {
             // Add choose account code here
             console.warn("Multiple accounts detected.");
          } else if (currentAccounts.length === 1) {
             username = currentAccounts[0].username;
             showWelcomeMessage(username);
          }
       }
    
       // Called by the loginButton
       function signIn() {
          myMSALObj.loginPopup({
             scopes: ["User.Read",baseUrl+"/user_impersonation"] //<= Includes Dataverse scope
             })
             .then(response =>{
                if (response !== null) {
                username = response.account.username;
                showWelcomeMessage(username);
                   } else {
                      selectAccount();
                   }
             })
             .catch(error => {
                   console.error(error);
             });
       }
    
       // Shows greeting and enables logoutButton and getAccountsButton
       // Called from signIn or selectAccount functions
       function showWelcomeMessage(username) {
        message.innerHTML = `Welcome ${username}`;
        loginButton.style.display = "none";
        logoutButton.style.display = "block";
        getAccountsButton.style.display = "block";
       }
    
       // Called by the logoutButton
       function signOut() {
    
          const logoutRequest = {
             account: myMSALObj.getAccountByUsername(username),
             postLogoutRedirectUri: msalConfig.auth.redirectUri,
             mainWindowRedirectUri: msalConfig.auth.redirectUri
          };
    
          myMSALObj.logoutPopup(logoutRequest);
       }
    
       // Provides the access token for a request, opening pop-up if necessary.
       // Used by GetAccounts function
       function getTokenPopup(request) {
    
          request.account = myMSALObj.getAccountByUsername(username);
    
          return myMSALObj.acquireTokenSilent(request)
             .catch(error => {
                   console.warn("Silent token acquisition fails. Acquiring token using popup");
                   if (error instanceof msal.InteractionRequiredAuthError) {
                      // fallback to interaction when silent call fails
                      return myMSALObj.acquireTokenPopup(request)
                         .then(tokenResponse => {
                               console.log(tokenResponse);
                               return tokenResponse;
                         }).catch(error => {
                               console.error(error);
                         });
                   } else {
                      console.warn(error);   
                   }
          });
       }
    
       // Retrieves top 10 account records from Dataverse
       function getAccounts(callback) {
          // Gets the access token
          getTokenPopup({
                scopes: [baseUrl+"/.default"]
             })
             .then(response => {
                getDataverse("accounts?$select=name,address1_city&$top=10", response.accessToken, callback);
             }).catch(error => {
                console.error(error);
             });
       }
    
       /** 
        * Helper function to get data from Dataverse
       * using the authorization bearer token scheme
       * callback is the writeTable function below
       */
       function getDataverse(url, token, callback) {
           const headers = new Headers();
           const bearer = `Bearer ${token}`;
           headers.append("Authorization", bearer);
           // Other Dataverse headers
           headers.append("Accept", "application/json"); 
           headers.append("OData-MaxVersion", "4.0");  
           headers.append("OData-Version", "4.0");  
    
           const options = {
              method: "GET",
              headers: headers
           };
    
         console.log('GET Request made to Dataverse at: ' + new Date().toString());
    
         fetch(webAPIEndpoint+"/"+url, options)
              .then(response => response.json())
              .then(response => callback(response))
              .catch(error => console.log(error));
        }
    
        // Renders the table with data from GetAccounts
        function writeTable(data) {
    
           data.value.forEach(function (account) {
    
               var name = account.name;
               var city = account.address1_city;
    
               var nameCell = document.createElement("td");
               nameCell.textContent = name;
    
               var cityCell = document.createElement("td");
               cityCell.textContent = city;
    
               var row = document.createElement("tr");
    
               row.appendChild(nameCell);
               row.appendChild(cityCell);
    
               accountsTableBody.appendChild(row); 
    
           });
    
           accountsTable.style.display = "block";
           getAccountsButton.style.display = "none";
        }
    
        selectAccount();
      </script>
     </body>
    </html>
    

    Notes

    Le code JavaScript de la page HTML a été adapté à partir de l’exemple de code publié ici : https://github.com/Azure-Samples/ms-identity-javascript-v2 qui se connecte à Microsoft Graph.

    La principale différence réside dans les étendues utilisées à l’obtention du jeton d’accès.

    Utilisez ces champs d’application pour le bouton de connexion :

      // Called by the loginButton
      function signIn() {
         myMSALObj.loginPopup({
            scopes: ["User.Read",baseUrl+"/user_impersonation"]  //<= Includes Dataverse scope
            })
    

    Ces étendues incluent à la fois l’étendue User.Read de Microsoft Graph, mais aussi l’étendue de user_impersonation de Dataverse. En incluant ces deux étendues à la connexion, la boîte de dialogue de consentement initiale inclura toutes les étendues nécessaires utilisées dans l’application.

    Ensuite, au moment de la spécification de l’étendue utilisée pour l’appel à Dataverse, vous pouvez utiliser /.default ou /user_impersonation.

          // Retrieves top 10 account records from Dataverse
          function getAccounts(callback) {
             // Gets the access token
             getTokenPopup({
                   scopes: [baseUrl+"/.default"]
                })
    

    L’étendue /user_impersonation ne fonctionne que pour les autorisations déléguées, ce qui est le cas ici, elle pourrait donc être utilisée. /.default fonctionne pour les autorisations déléguées et d’application.

    Si vous n’incluez pas l’étendue baseUrl+"/user_impersonation" au moment de la connexion, l’utilisateur devra consentir une deuxième fois quand il cliquera sur le bouton Obtenir des comptes pour la première fois.

    Vous pouvez trouver d’autres exemples et tutoriels SPA ici : Documentation d’application monopage (SPA).

  5. Dans la page index.html, recherchez les variables de configuration suivantes et définissez-les à l’aide des informations que vous avez recueillies aux étapes précédentes : Obtenir votre point de terminaison API web Dataverse et Enregistrer votre application.

    const baseUrl = "https://org.api.crm.dynamics.com";      //<= Change this
    const clientId = "11111111-1111-1111-1111-111111111111"; //<= Change this
    const tenantId = "22222222-2222-2222-2222-222222222222"; //<= Change this
    

Déboguer l’application

Parce que vous avez installé l’extension Live Server dans Installer l’extension Live Server de Visual Studio Code, dans la barre d’outils de VS Code vous devriez trouver ce bouton : .

  1. Cliquez sur le bouton Mettre en service et une nouvelle fenêtre de navigateur s’ouvrira pour le rendu http://localhost:5500/index.html de la page index.html.

    La première fois que vous exécutez l’application et cliquez sur le bouton Connexion, vous obtiendrez une boîte de dialogue de consentement comme celle-ci :

    Boîte de dialogue Autorisations demandées

    Si vous êtes administrateur, vous pouvez cocher la case Consentement au nom de votre organisation qui permettra aux autres d’exécuter également l’application sans avoir à utiliser la boîte de dialogue Autorisations demandées.

  2. Cliquez sur Accepter pour continuer les tests afin de vérifier que l’application fonctionne comme décrit dans Objectif de ce démarrage rapide.

Dépannage

L’expérience de ce démarrage rapide dépend du paramètre du port de Server Live comme valeur par défaut : 5500. Si vous avez déjà installé Live Server et que vous avez modifié le paramètre de port, vous devrez modifier le paramètre par défaut ou l’URL définie à l’enregistrement de l’application.

Notez que le liveServer.settings.port peut également être défini pour Espace de travail et remplacera le paramètre Utilisateur.

Si vous ouvrez plusieurs instances de Live Server, le paramètre de port peut passer à 5501 ou plus. Cela interrompra le rappel utilisé pour l’authentification, car le port est « codé en dur » dans l’enregistrement de l’application en tant que http://localhost:5500/index.html.

Voir aussi

Documentation sur l’application sur une seule page (SPA)
Utiliser OAuth avec le partage des ressources cross-origin pour connecter une application sur une seule page à Dataverse
Créer des applications clientes

Notes

Pouvez-vous nous indiquer vos préférences de langue pour la documentation ? Répondez à un court questionnaire. (veuillez noter que ce questionnaire est en anglais)

Le questionnaire vous prendra environ sept minutes. Aucune donnée personnelle n’est collectée (déclaration de confidentialité).