Freigeben über


Schnellstart: Registrieren und konfigurieren Sie eine SPA-Anwendung für Dataverse mit msal.js

Dieses Thema beschreibt den Prozess der Registrierung und Konfiguration der einfachsten Single-Page-Application (SPA) für den Zugriff auf Daten in Microsoft Dataverse unter Verwendung von msal.js und Cross-Origin Resource Sharing (CORS). Weitere Informationen: Verwenden Sie OAuth mit Cross-Origin Resource Sharing, um eine Single-Page-Applikation mit Dataverse zu verbinden.

Anforderungen

Ziel dieses Schnellstarts

Wenn Sie diesen Schnellstart abschließen, können Sie eine einfache SPA-Anwendung ausführen, über die sich der Benutzer authentifizieren und Daten aus Dataverse abrufen kann.

Wenn Sie die Anwendung debuggen, gibt es zunächst nur eine Schaltfläche Anmelden.

  • Klicken Sie auf Anmeldung, ein Popup-Fenster wird geöffnet, um Ihre Anmeldeinformationen einzugeben.

  • Nachdem Sie Ihre Anmeldeinformationen eingegeben haben, ist die Schaltflächen Anmelden ausgeblendet und Schaltflächen für Abmelden und Firmen abrufen werden angezeigt. Sie sehen außerdem eine Begrüßung mit Informationen zu Ihrem Benutzerkonto.

  • Klicken Sie auf die Schaltfläche Firmen abrufen, um 10 Firmendatensätze aus Ihrer Dataverse-Organisation abzurufen. Das Ergebnis wird im folgenden Screenshot angezeigt:

    Die SimpleSPA-Seite.

  • Schließlich können Sie auf die Schaltfläche Abmelden klicken, um sich abzumelden.

Hinweis

Diese SPA-Anwendung ist nicht als Muster zum Entwickeln von SPA-Anwendungen vorgesehen. Sie dient nur zu Beschreibung des Vorgangs der Registrierung und Konfiguration der Anwendung.

Ihren Dataverse Web-API Endpunkt abrufen

Verwenden Sie die Anweisungen in Entwicklerressourcen anzeigen, um eine Web-API Endpunkt für eine Umgebung zu identifizieren, auf die Sie zugreifen können. Sie sollte ungefähr so aussehen: https://yourorg.api.crm.dynamics.com/api/data/v9.2.

Registrieren Ihrer Anwendung

  1. Erweitern Sie im Power Platform Admin Center in der linken Navigation Admin Center und wählen Sie Microsoft Entra ID aus.

    Microsoft Entra ID vom Power Platform Admin Center

    So öffnen Sie das Microsoft Entra Admin Center

  2. Erweitern Sie Anwendungen und wählen Sie App-Registrierungen aus.

    Registrierungen von Azure Apps aus dem Microsoft Entra Admin Center

  3. Klicken Sie auf Neue Registrierung. Dies öffnet das Formular Eine Anwendung registrieren.

    Registrieren und Anmeldeformular.

  4. Geben Sie unter Eine Anwendung registrieren einen Namen ein. Verwenden Sie für diesen Schnellstart den Namen Einfache SPA.

  5. Für Unterstützte Kontotypen, sollte die Standardauswahl folgendermaßen sein:
    Nur Konten in diesem Organisationsverzeichnis (nur <Mandatenname> – einzelner Mandant). Nehmen Sie hier keine Änderungen vor.

  6. Als Umleitungs-URI (optional) verwenden Sie diese Optionen:

    • Eine Plattform auswählen: Einzelseitenanwendung (SPA)
    • e.g. https://example.com/auth: http://localhost:5500/index.html
  7. Klicken Sie auf Registrieren.

  8. Kopieren Sie im Überblick-Bereich die folgenden Werte, da Sie sie im letzten Schritt von Erstellen eines Webanwendungsprojekts benötigen.

    • Anwendungs(client)-ID
    • Verzeichnis (Mandant) ID
  9. Wählen Sie API-Berechtigungen aus.

  10. Klicken Sie auf Berechtigung hinzufügen.

  11. In dem Fly-Out API-Berechtigungen anfordern wählen Sie Dynamics CRM aus.

    • Wenn Sie Dynamics CRMnicht sehen, suchen Sie nach Dataverse. Oder wählen Sie die Registerkarte Von meiner Organisation verwendete APIs aus und suchen Sie nach Dataverse.
  12. Wählen Sie die delegierte user_impersonation-Berechtigung aus.

  13. Klicken Sie auf Berechtigungen hinzufügen.

Die konfigurierten Berechtigungen sollten wie folgt aussehen, wenn Sie fertig sind:

Konfigurierte Berechtigungen für die Simple SPA-App

Live-Server Visual Studio Code-Erweiterung installieren

Live-Server ist eine Visual Studio Code-Erweiterung, mit der Sie ganz einfach einen lokalen Entwicklungsserver für Webseiten starten können.

  1. Befolgen Sie diese Anweisungen, um die Live Server-Erweiterung für VS Code im VS Code Marketplace zu finden und zu installieren:

  2. Nachdem Sie die Live Server-Erweiterung installiert haben, nehmen Sie diese Änderungen an den Standardeinstellungen vor.

  3. Klicken Sie auf das Zahnradsymbol in VS Code und wählen Sie Einstellungen aus, oder verwenden Sie das Ctrl+,-Tastaturkürzel.

  4. Geben Sie liveServer.settings.host in das Suchfenster ein und ändern Sie den Standardwert von 127.0.0.1 zu localhost.

Erstellen eines Webanwendungsprojekts

  1. Erstellen Sie einen Ordner auf Ihrem Computer. Der Name ist nicht wichtig, aber für den Zweck dieser Anweisungen nennen Sie ihn simplespa.

  2. Öffnen Sie VS Code und wählen Sie im Menü Datei > Ordner öffnen aus. Wählen Sie den Ordner simplespa aus.

  3. Erstellen Sie eine neue HTML-Datei im Ordner namens index.html. (Nicht index.htm)

  4. Kopieren Sie den folgenden Inhalt in die Datei 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>
    

    Hinweis

    Der JavaScript-Code in der HTML-Seite wurde aus dem hier veröffentlichten Beispielcode angepasst: https://github.com/Azure-Samples/ms-identity-javascript-v2, der eine Verbindung mit Microsoft Graph herstellt.

    Der Hauptunterschied besteht in den Bereichen, die beim Abrufen von Zugriffstoken verwendet werden.

    Verwenden Sie diese Bereiche für die Anmeldeschaltfläche:

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

    Diese Bereiche umfassen sowohl Microsoft Graph User.Read-Umfang als auch den Dataverseuser_impersonation-Umfang. Durch die Einbeziehung dieser beiden Bereiche bei der Anmeldung enthält der anfängliche Zustimmungsdialog alle erforderlichen Bereiche, die in der Anwendung verwendet werden.

    Wenn Sie dann den Bereich angeben, der für den Aufruf von Dataverse verwendet wird, können Sie /.default oder /user_impersonation verwenden.

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

    Der /user_impersonation-Umfang funktioniert nur für delegierte Berechtigungen, was hier der Fall ist, sodass er verwendet werden könnte. /.default funktioniert sowohl für delegierte als auch für Anwendungsberechtigungen.

    Wenn Sie den baseUrl+"/user_impersonation"-Umfang beim Einloggen nicht einschließen, muss der Benutzer ein zweites Mal zustimmen, wenn er zum ersten Mal auf die Schaltfläche Konten abrufen klickt.

    Weitere SPA-Beispiele und Tutorials finden Sie hier: Dokumentation für einseitige Anwendungen (SPA)..

  5. Suchen Sie auf der Seite Index.html die folgenden Konfigurationsvariablen und legen Sie sie mit den Informationen fest, die Sie in früheren Schritten gesammelt haben: Ihren Dataverse Web-API Endpunkt abrufen und Ihre Anwendung registrieren.

    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
    

App debuggen

Weil Sie die Live Server-Erweiterung in Live-Server Visual Studio Code-Erweiterung installieren installiert haben, sollten Sie diese Schaltfläche in der VS Code-Symbolleiste finden: .

  1. Klicken Sie auf die Schaltfläche Aktiv schalten und ein neues Browserfenster öffnet sich unter http://localhost:5500/index.html und rendert die Seite Index.html.

    Wenn Sie die App zum ersten Mal ausführen und auf die Anmelden-Schaltfläche klicken, erhalten Sie einen Zustimmungsdialog wie diesen:

    Berechtigungsanforderungsdialog

    Wenn Sie ein Administrator sind, können Sie das Zustimmung im Namen Ihrer Organisation-Kontrollkästchen aktivieren, das es anderen ermöglicht, die App ebenfalls auszuführen, ohne den Berechtigungen angefordert-Dialog verwenden zu müssen.

  2. Klicken Sie auf Annehmen, um mit dem Testen fortzufahren, um sicherzustellen, dass die App wie in Ziel dieses Schnellstarts beschrieben funktioniert.

Problembehandlung

Die Erfahrung in diesem Schnellstart hängt davon ab, ob die Live Server-Porteinstellung der Standardwert ist: 5500. Wenn Sie Live Server bereits installiert und die Porteinstellung geändert haben, müssen Sie die Standardeinstellung oder die in der App-Registrierung festgelegte URL ändern.

Bitte beachten Sie, dass der liveServer.settings.port auch für den Arbeitsbereich festgelegt werden kann und die Benutzer-Einstellung überschreiben wird.

Wenn Sie mehrere Live Server-Instanzen öffnen, wird die Porteinstellung möglicherweise auf 5501 oder höher erhöht. Dadurch wird der für die Authentifizierung verwendete Rückruf unterbrochen, da der Port in der Anwendungsregistrierung als http://localhost:5500/index.html „fest codiert“ ist.

Siehe auch

Dokumentation für Einzelseitenanwendungen (SPA)
Verwenden Sie OAuth mit herkunftsübergreifender Ressourcenfreigabe, um eine Single-Page-Anwendung mit Dataverse zu verbinden
Erstellen von Client-Anwendungen

Hinweis

Können Sie uns Ihre Präferenzen für die Dokumentationssprache mitteilen? Nehmen Sie an einer kurzen Umfrage teil. (Beachten Sie, dass diese Umfrage auf Englisch ist.)

Die Umfrage dauert etwa sieben Minuten. Es werden keine personenbezogenen Daten erhoben. (Datenschutzbestimmungen).