Esercitazione: Accedere agli utenti e chiamare l'API Microsoft Graph da un'app a pagina singola JavaScript usando il flusso del codice di autenticazione

In questa esercitazione verrà creata un'applicazione a pagina singola JavaScript che concede l'accesso agli utenti e chiama Microsoft Graph usando il flusso del codice di autorizzazione con PKCE. L'applicazione a pagina singola creata usa Microsoft Authentication Library (MSAL) per JavaScript v2.0.

Contenuto dell'esercitazione:

  • Eseguire il flusso del codice di autorizzazione OAuth 2.0 con PKCE
  • Accedere agli account Microsoft personali, oltre che agli account aziendali e dell'istituto di istruzione
  • Acquisire un token di accesso
  • Chiamare Microsoft Graph o l'API personalizzata che richiede token di accesso ottenuti da Microsoft Identity Platform

MSAL.js 2.0 rappresenta un miglioramento rispetto a MSAL.js 1.0 in quanto supporta il flusso del codice di autorizzazione nel browser invece del flusso di concessione implicita. MSAL.js 2.0 NON supporta il flusso implicito.

Prerequisiti

Funzionamento dell'app dell'esercitazione

Diagram showing the authorization code flow in a single-page application

L'applicazione creata in questa esercitazione consente a un'applicazione a pagina singola JavaScript di eseguire query sull'API Microsoft Graph acquisendo token di sicurezza da Microsoft Identity Platform. Per questo scenario, dopo l'accesso di un utente, viene richiesto e aggiunto un token di accesso alle richieste HTTP nell'intestazione dell'autorizzazione. L'acquisizione e il rinnovo del token vengono gestiti da Microsoft Authentication Library (MSAL.js) per JavaScript.

Questa esercitazione usa MSAL.js, il pacchetto del browser Microsoft Authentication Library per JavaScript v2.0.

Ottenere l'esempio di codice completo

È possibile scaricare il progetto di esempio completo di questa esercitazione clonando invece il repository ms-identity-javascript-v2 .

git clone https://github.com/Azure-Samples/ms-identity-javascript-v2.git

Per eseguire il progetto scaricato nell'ambiente di sviluppo locale, iniziare creando un server localhost per l'applicazione come descritto nel passaggio 1 della creazione del progetto. Al termine, è possibile configurare l'esempio di codice ignorando il passaggio di configurazione.

Per continuare con l'esercitazione e compilare manualmente l'applicazione, passare alla sezione successiva Creare il progetto.

Creare il progetto

Dopo aver Node.js installato, creare una cartella per ospitare l'applicazione, ad esempio msal-spa-tutorial.

Implementare quindi un piccolo server Web Express per gestire il file index.html.

  1. Per prima cosa, passare alla cartella del progetto nel terminale e quindi eseguire i comandi npm seguenti:

    npm init -y
    npm install @azure/msal-browser
    npm install express
    npm install morgan
    npm install yargs
    
  2. Successivamente, creare un file denominato server.js e aggiungere il codice seguente:

    const express = require('express');
    const morgan = require('morgan');
    const path = require('path');
    
    const DEFAULT_PORT = process.env.PORT || 3000;
    
    // initialize express.
    const app = express();
    
    // Initialize variables.
    let port = DEFAULT_PORT;
    
    // Configure morgan module to log all requests.
    app.use(morgan('dev'));
    
    // Setup app folders.
    app.use(express.static('app'));
    
    // Set up a route for index.html
    app.get('*', (req, res) => {
        res.sendFile(path.join(__dirname + '/index.html'));
    });
    
    // Start the server.
    app.listen(port);
    console.log(`Listening on port ${port}...`);
    

Creare l'interfaccia utente SPA

  1. Creare una cartella app nella directory del progetto e al suo interno creare un file index.html per l'applicazione a pagina singola JavaScript. Questo file implementa un'interfaccia utente creata con Bootstrap 4 Framework e importa i file di script per la configurazione, l'autenticazione e le chiamate API.

    Nel file index.html aggiungere il codice seguente:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
      <title>Microsoft identity platform</title>
      <link rel="SHORTCUT ICON" href="./favicon.svg" type="image/x-icon">
    
       <!-- msal.min.js can be used in the place of msal.js; included msal.js to make debug easy -->
      <script src="https://alcdn.msauth.net/browser/2.30.0/js/msal-browser.js"
        integrity="sha384-o4ufwq3oKqc7IoCcR08YtZXmgOljhTggRwxP2CLbSqeXGtitAxwYaUln/05nJjit"
        crossorigin="anonymous"></script>
      
      <!-- adding Bootstrap 4 for UI components  -->
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
      <link rel="SHORTCUT ICON" href="https://c.s-microsoft.com/favicon.ico?v2" type="image/x-icon">
    </head>
    
    <body>
      <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
        <a class="navbar-brand" href="/">Microsoft identity platform</a>
        <div class="btn-group ml-auto dropleft">
          <button type="button" id="SignIn" class="btn btn-secondary" onclick="signIn()">
            Sign In
          </button>
        </div>
      </nav>
      <br>
      <h5 class="card-header text-center">Vanilla JavaScript SPA calling MS Graph API with MSAL.js</h5>
      <br>
      <div class="row" style="margin:auto">
        <div id="card-div" class="col-md-3" style="display:none">
          <div class="card text-center">
            <div class="card-body">
              <h5 class="card-title" id="WelcomeMessage">Please sign-in to see your profile and read your mails</h5>
              <div id="profile-div"></div>
              <br>
              <br>
              <button class="btn btn-primary" id="seeProfile" onclick="seeProfile()">See Profile</button>
              <br>
              <br>
              <button class="btn btn-primary" id="readMail" onclick="readMail()">Read Mails</button>
            </div>
          </div>
        </div>
        <br>
        <br>
        <div class="col-md-4">
          <div class="list-group" id="list-tab" role="tablist">
          </div>
        </div>
        <div class="col-md-5">
          <div class="tab-content" id="nav-tabContent">
          </div>
        </div>
      </div>
      <br>
      <br>
    
      <!-- importing bootstrap.js and supporting js libraries -->
      <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
        integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
        crossorigin="anonymous"></script>
      <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
        integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
        crossorigin="anonymous"></script>
      <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
        integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
        crossorigin="anonymous"></script>
    
      <!-- importing app scripts (load order is important) -->
      <script type="text/javascript" src="./authConfig.js"></script>
      <script type="text/javascript" src="./graphConfig.js"></script>
      <script type="text/javascript" src="./ui.js"></script>
    
      <!-- <script type="text/javascript" src="./authRedirect.js"></script>   -->
      <!-- uncomment the above line and comment the line below if you would like to use the redirect flow -->
      <script type="text/javascript" src="./authPopup.js"></script>
      <script type="text/javascript" src="./graph.js"></script>
    </body>
    
    </html>
    
  2. Quindi, sempre nella cartella app, creare un file denominato ui.js e aggiungere il codice seguente. Questo file accede agli elementi DOM e li aggiorna.

    // Select DOM elements to work with
    const welcomeDiv = document.getElementById("WelcomeMessage");
    const signInButton = document.getElementById("SignIn");
    const cardDiv = document.getElementById("card-div");
    const mailButton = document.getElementById("readMail");
    const profileButton = document.getElementById("seeProfile");
    const profileDiv = document.getElementById("profile-div");
    
    function showWelcomeMessage(username) {
        // Reconfiguring DOM elements
        cardDiv.style.display = 'initial';
        welcomeDiv.innerHTML = `Welcome ${username}`;
        signInButton.setAttribute("onclick", "signOut();");
        signInButton.setAttribute('class', "btn btn-success")
        signInButton.innerHTML = "Sign Out";
    }
    
    function updateUI(data, endpoint) {
        console.log('Graph API responded at: ' + new Date().toString());
    
        if (endpoint === graphConfig.graphMeEndpoint) {
            profileDiv.innerHTML = ''
            const title = document.createElement('p');
            title.innerHTML = "<strong>Title: </strong>" + data.jobTitle;
            const email = document.createElement('p');
            email.innerHTML = "<strong>Mail: </strong>" + data.mail;
            const phone = document.createElement('p');
            phone.innerHTML = "<strong>Phone: </strong>" + data.businessPhones[0];
            const address = document.createElement('p');
            address.innerHTML = "<strong>Location: </strong>" + data.officeLocation;
            profileDiv.appendChild(title);
            profileDiv.appendChild(email);
            profileDiv.appendChild(phone);
            profileDiv.appendChild(address);
    
        } else if (endpoint === graphConfig.graphMailEndpoint) {
            if (!data.value) {
                alert("You do not have a mailbox!")
            } else if (data.value.length < 1) {
                alert("Your mailbox is empty!")
            } else {
                const tabContent = document.getElementById("nav-tabContent");
                const tabList = document.getElementById("list-tab");
                tabList.innerHTML = ''; // clear tabList at each readMail call
    
                data.value.map((d, i) => {
                    // Keeping it simple
                    if (i < 10) {
                        const listItem = document.createElement("a");
                        listItem.setAttribute("class", "list-group-item list-group-item-action")
                        listItem.setAttribute("id", "list" + i + "list")
                        listItem.setAttribute("data-toggle", "list")
                        listItem.setAttribute("href", "#list" + i)
                        listItem.setAttribute("role", "tab")
                        listItem.setAttribute("aria-controls", i)
                        listItem.innerHTML = d.subject;
                        tabList.appendChild(listItem)
    
                        const contentItem = document.createElement("div");
                        contentItem.setAttribute("class", "tab-pane fade")
                        contentItem.setAttribute("id", "list" + i)
                        contentItem.setAttribute("role", "tabpanel")
                        contentItem.setAttribute("aria-labelledby", "list" + i + "list")
                        contentItem.innerHTML = "<strong> from: " + d.from.emailAddress.address + "</strong><br><br>" + d.bodyPreview + "...";
                        tabContent.appendChild(contentItem);
                    }
                });
            }
        }
    }
    

Registrare l'applicazione

Seguire la procedura descritta in Applicazione a pagina singola: Registrazione app per creare una registrazione dell'app per l'applicazione a pagina singola.

Nell'URI di reindirizzamento : MSAL.js 2.0 con il passaggio del flusso del codice di autenticazione immettere http://localhost:3000, il percorso predefinito in cui viene eseguita l'applicazione dell'esercitazione.

Se si vuole usare una porta diversa, immettere http://localhost:<port>, dove <port> è il numero di porta TCP preferito. Se si specifica un numero di porta diverso da 3000, aggiornare anche server.js con tale numero.

Configurare JavaScript SPA

Creare un file denominato authConfig.js nella cartella app, che conterrà i parametri di configurazione per l'autenticazione, e quindi aggiungere il codice seguente:

/**
 * Configuration object to be passed to MSAL instance on creation. 
 * For a full list of MSAL.js configuration parameters, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md 
 */
const msalConfig = {
    auth: {
        // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
        clientId: "Enter_the_Application_Id_Here",
        // Full directory URL, in the form of https://login.microsoftonline.com/<tenant-id>
        authority: "Enter_the_Cloud_Instance_Id_HereEnter_the_Tenant_Info_Here",
        // Full redirect URL, in form of http://localhost:3000
        redirectUri: "Enter_the_Redirect_Uri_Here",
    },
    cache: {
        cacheLocation: "sessionStorage", // This configures where your cache will be stored
        storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
    },
    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;		
                }	
            }	
        }	
    }
};

/**
 * Scopes you add here will be prompted for user consent during sign-in.
 * By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request.
 * For more information about OIDC scopes, visit: 
 * https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
 */
const loginRequest = {
    scopes: ["User.Read"]
};

/**
 * Add here the scopes to request when obtaining an access token for MS Graph API. For more information, see:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/resources-and-scopes.md
 */
const tokenRequest = {
    scopes: ["User.Read", "Mail.Read"],
    forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token
};

Sempre nella cartella app creare un file denominato graphConfig.js. Aggiungere il codice seguente per fornire all'applicazione i parametri di configurazione per chiamare l'API Microsoft Graph:

// Add here the endpoints for MS Graph API services you would like to use.
const graphConfig = {
    graphMeEndpoint: "Enter_the_Graph_Endpoint_Herev1.0/me",
    graphMailEndpoint: "Enter_the_Graph_Endpoint_Herev1.0/me/messages"
};

Modificare i valori nella sezione graphConfig come descritto di seguito:

  • Enter_the_Graph_Endpoint_Here è l'istanza dell'API Microsoft Graph con cui l'applicazione dovrà comunicare.
    • Per l'endpoint API Microsoft Graph globale, sostituire entrambe le istanze di questa stringa con https://graph.microsoft.com.
    • Per gli endpoint delle distribuzioni di cloud nazionali, vedere Distribuzioni di cloud nazionali nella documentazione di Microsoft Graph.

Se si usa l'endpoint globale, i valori graphMeEndpoint e graphMailEndpoint nel file graphConfig.js dovranno essere simili ai seguenti:

graphMeEndpoint: "https://graph.microsoft.com/v1.0/me",
graphMailEndpoint: "https://graph.microsoft.com/v1.0/me/messages"

Usare Microsoft Authentication Library (MSAL) per l'accesso dell'utente

Popup

Nella cartella app creare un file denominato authPopup.js e aggiungere il codice di autenticazione e di acquisizione di token seguente per la finestra popup di accesso:

// Create the main myMSALObj instance
// configuration parameters are located at authConfig.js
const myMSALObj = new msal.PublicClientApplication(msalConfig);

let username = "";

function selectAccount() {

    /**
     * See here for more info on account retrieval: 
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
     */

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

function handleResponse(response) {

    /**
     * To see the full list of response object properties, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#response
     */

    if (response !== null) {
        username = response.account.username;
        showWelcomeMessage(username);
    } else {
        selectAccount();
    }
}

function signIn() {

    /**
     * You can pass a custom request object below. This will override the initial configuration. For more information, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
     */

    myMSALObj.loginPopup(loginRequest)
        .then(handleResponse)
        .catch(error => {
            console.error(error);
        });
}

function signOut() {

    /**
     * You can pass a custom request object below. This will override the initial configuration. For more information, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
     */

    const logoutRequest = {
        account: myMSALObj.getAccountByUsername(username),
        postLogoutRedirectUri: msalConfig.auth.redirectUri,
        mainWindowRedirectUri: msalConfig.auth.redirectUri
    };

    myMSALObj.logoutPopup(logoutRequest);
}

function getTokenPopup(request) {

    /**
     * See here for more info on account retrieval: 
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
     */
    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);   
            }
    });
}

function seeProfile() {
    getTokenPopup(loginRequest)
        .then(response => {
            callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI);
        }).catch(error => {
            console.error(error);
        });
}

function readMail() {
    getTokenPopup(tokenRequest)
        .then(response => {
            callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI);
        }).catch(error => {
            console.error(error);
        });
}

selectAccount();

Reindirizza

Creare un file denominato authRedirect.js nella cartella app e aggiungere il codice di autenticazione e di acquisizione di token seguente per il reindirizzamento dell'account di accesso:

// Create the main myMSALObj instance
// configuration parameters are located at authConfig.js
const myMSALObj = new msal.PublicClientApplication(msalConfig);

let username = "";

/**
 * A promise handler needs to be registered for handling the
 * response returned from redirect flow. For more information, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/acquire-token.md
 */
myMSALObj.handleRedirectPromise()
    .then(handleResponse)
    .catch((error) => {
        console.error(error);
    });

function selectAccount () {

    /**
     * See here for more info on account retrieval: 
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
     */

    const currentAccounts = myMSALObj.getAllAccounts();

    if (currentAccounts.length === 0) {
        return;
    } else if (currentAccounts.length > 1) {
        // Add your account choosing logic here
        console.warn("Multiple accounts detected.");
    } else if (currentAccounts.length === 1) {
        username = currentAccounts[0].username;
        showWelcomeMessage(username);
    }
}

function handleResponse(response) {
    if (response !== null) {
        username = response.account.username;
        showWelcomeMessage(username);
    } else {
        selectAccount();
    }
}

function signIn() {

    /**
     * You can pass a custom request object below. This will override the initial configuration. For more information, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
     */

    myMSALObj.loginRedirect(loginRequest);
}

function signOut() {

    /**
     * You can pass a custom request object below. This will override the initial configuration. For more information, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
     */

    const logoutRequest = {
        account: myMSALObj.getAccountByUsername(username),
        postLogoutRedirectUri: msalConfig.auth.redirectUri,
    };

    myMSALObj.logoutRedirect(logoutRequest);
}

function getTokenRedirect(request) {
    /**
     * See here for more info on account retrieval: 
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
     */
    request.account = myMSALObj.getAccountByUsername(username);

    return myMSALObj.acquireTokenSilent(request)
        .catch(error => {
            console.warn("silent token acquisition fails. acquiring token using redirect");
            if (error instanceof msal.InteractionRequiredAuthError) {
                // fallback to interaction when silent call fails
                return myMSALObj.acquireTokenRedirect(request);
            } else {
                console.warn(error);   
            }
        });
}

function seeProfile() {
    getTokenRedirect(loginRequest)
        .then(response => {
            callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI);
        }).catch(error => {
            console.error(error);
        });
}

function readMail() {
    getTokenRedirect(tokenRequest)
        .then(response => {
            callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI);
        }).catch(error => {
            console.error(error);
        });
}

Funzionamento del codice

Quando un utente seleziona il pulsante Accedi per la prima volta, il metodo signIn chiama loginPopup per farlo accedere. Il metodo loginPopup apre una finestra popup con l'endpoint di Microsoft Identity Platform per la richiesta e la convalida delle credenziali dell'utente. Dopo aver eseguito l'accesso, msal.js avvia il flusso di Codice di autorizzazione.

A questo punto, un codice di autorizzazione protetto da PKCE viene inviato all'endpoint token protetto da CORS e viene sostituito con i token. L'applicazione riceve un token ID, un token di accesso e un token di aggiornamento, che vengono quindi elaborati da msal.js, quindi le informazioni contenute nei token vengono memorizzate nella cache.

Il token ID contiene informazioni di base sull'utente, ad esempio il nome visualizzato. Se si prevede di usare i dati forniti dal token ID, il server back-end deve convalidarlo per garantire che sia stato emesso a un utente valido per l'applicazione.

Il token di accesso ha una durata limitata e scade dopo 24 ore. Il token di aggiornamento può essere usato per acquisire automaticamente nuovi token di accesso.

L'applicazione a pagina singola creata in questa esercitazione chiama acquireTokenSilent e/o acquireTokenPopup per acquisire un token di accesso usato per eseguire una query sull'API Microsoft Graph e trovare le informazioni del profilo utente. Se è necessario un esempio che convalidi il token ID, vedere l'applicazione di esempio active-directory-javascript-singlepageapp-dotnet-webapi-v2 in GitHub. Nell'esempio viene usata un'API Web ASP.NET per la convalida dei token.

Ottenere un token utente in modo interattivo

Dopo l'accesso iniziale, l'app non dovrà chiedere agli utenti di ripetere l'autenticazione (ossia, non dovrà richiedere un token) ogni volta che vogliono accedere a una risorsa protetta. Per impedire tali richieste di riautenticazione, chiamare acquireTokenSilent. In alcune situazioni, tuttavia, può essere necessario forzare gli utenti a interagire con Microsoft Identity Platform. Ad esempio:

  • Gli utenti devono reimmettere le proprie credenziali perché la password è scaduta.
  • L'applicazione richiede l'accesso a una risorsa per cui è necessario il consenso dell'utente.
  • È necessaria l'autenticazione a due fattori.

La chiamata acquireTokenPopup apre una finestra popup (o acquireTokenRedirect reindirizza gli utenti a Microsoft Identity Platform). In questa finestra gli utenti devono interagire confermando le proprie credenziali, fornendo il consenso per la risorsa necessaria o completando l'autenticazione a due fattori.

Ottenere un token utente in modo automatico

Il metodo acquireTokenSilent gestisce le acquisizioni e i rinnovi dei token senza alcuna interazione da parte dell'utente. Dopo aver eseguito il metodo loginPopup o loginRedirect la prima volta, per le chiamate successive il metodo comunemente usato per ottenere i token usati per accedere a risorse protette è acquireTokenSilent. Le chiamate per richiedere o rinnovare i token vengono eseguite in modo invisibile per l'utente. acquireTokenSilent potrebbe non riuscire in alcuni casi. È ad esempio possibile che la password dell'utente sia scaduta. L'applicazione può gestire questa eccezione in due modi:

  1. Effettuare immediatamente una chiamata a acquireTokenPopup per attivare una richiesta di accesso utente. Questo modello viene in genere usato nelle applicazioni online in cui non è disponibile per l'utente contenuto non autenticato. L'esempio generato da questa configurazione guidata usa questo modello.
  2. Usare un'indicazione visiva per informare l'utente che è necessario un accesso interattivo, in modo da consentire di scegliere il momento più opportuno per accedere. In alternativa, l'applicazione riproverà a eseguire acquireTokenSilent in un secondo momento. Questa tecnica viene in genere usata quando l'utente può usare altre funzionalità dell'applicazione senza subire interruzioni. Ad esempio, nell'applicazione potrebbe essere disponibile contenuto non autenticato. In questa situazione, l'utente può decidere se vuole eseguire l'accesso per accedere alla risorsa protetta oppure aggiornare le informazioni obsolete.

Nota

Questa esercitazione usa i metodi loginPopup e acquireTokenPopup per impostazione predefinita. Se si usa Internet Explorer, è consigliabile usare i metodi loginRedirect e acquireTokenRedirect a causa di un problema noto di Internet Explorer con le finestre popup. Ad esempio per ottenere lo stesso risultato con metodi di reindirizzamento diversi, vedere authRedirect.js in GitHub.

Chiamare l'API Microsoft Graph

Creare un file denominato graph.js nella cartella app e aggiungere il codice seguente per eseguire chiamate REST all'API Microsoft Graph:

/** 
 * Helper function to call MS Graph API endpoint
 * using the authorization bearer token scheme
*/
function callMSGraph(endpoint, token, callback) {
    const headers = new Headers();
    const bearer = `Bearer ${token}`;

    headers.append("Authorization", bearer);

    const options = {
        method: "GET",
        headers: headers
    };

    console.log('request made to Graph API at: ' + new Date().toString());

    fetch(endpoint, options)
        .then(response => response.json())
        .then(response => callback(response, endpoint))
        .catch(error => console.log(error));
}

Nell'applicazione di esempio creata in questa esercitazione viene usato il metodo callMSGraph() per eseguire una richiesta HTTP GET di una risorsa protetta che richiede un token. La richiesta restituisce quindi il contenuto al chiamante. Questo metodo aggiunge il token acquisito nell'intestazione di autorizzazione HTTP. Nell'applicazione di esempio creata in questa esercitazione la risorsa protetta è l'endpoint me dell'API Microsoft Graph, che visualizza informazioni sul profilo dell'utente connesso.

Testare l'applicazione

La creazione dell'applicazione è stata completata ed è ora possibile avviare il server Web Node.js e testarne la funzionalità.

  1. Avviare il server Web Node.js eseguendo i comandi seguenti all'interno della radice della cartella del progetto:

    npm start
    
  2. Nel browser passare a http://localhost:3000 o http://localhost:<port>, dove <port> è la porta su cui il server Web è in ascolto. Dovrebbero essere visibili il contenuto del file index.html e il pulsante Accedi.

Accedere all'applicazione

Dopo che il browser ha caricato il file index.html, fare clic su Accedi. Viene richiesto di accedere con Microsoft Identity Platform:

Web browser displaying sign-in dialog

La prima volta che si accede all'applicazione, viene chiesto di concedere l'accesso al proprio profilo e viene eseguito l'accesso:

Content dialog displayed in web browser

Se si acconsente alle autorizzazioni richieste, l'applicazione Web visualizza il nome utente, firmando un account di accesso riuscito:

Results of a successful sign-in in the web browser

Chiamare l'API Graph

Dopo aver eseguito l'accesso, selezionare See Profile (Vedi profilo) per visualizzare le informazioni del profilo utente restituite in una risposta dalla chiamata all'API Microsoft Graph:

Profile information from Microsoft Graph displayed in the browser

Altre informazioni sugli ambiti e sulle autorizzazioni delegate

L'API Microsoft Graph richiede l'ambito user.read per leggere il profilo dell'utente. Per impostazione predefinita, questo ambito viene aggiunto automaticamente in ogni applicazione registrata nell'interfaccia di amministrazione di Microsoft Entra. Altre API per Microsoft Graph e le API personalizzate per il server di back-end potrebbero richiedere anche altri ambiti. Ad esempio, l'API Microsoft Graph richiede l'ambito Mail.Read per visualizzare la posta elettronica dell'utente.

Quando si aggiungono ambiti, agli utenti potrebbe essere richiesto di fornire un consenso aggiuntivo.

Se per un'API back-end non è richiesto alcun ambito (non consigliabile), è possibile usare clientId come ambito nelle chiamate per acquisire i token.

Assistenza e supporto

Se è necessaria assistenza, si vuole segnalare un problema o si vogliono ottenere informazioni sulle opzioni di supporto, vedere Assistenza e supporto per gli sviluppatori.

Passaggi successivi

  • Per altre informazioni, è possibile creare un'applicazione a pagina singola React che consente agli utenti di accedere alla serie di esercitazioni in più parti seguente.