Esercitazione: Accedere agli utenti e chiamare Microsoft API Graph da un'app a pagina singola (SPA) React usando il flusso di codice di autenticazione

In questa esercitazione viene creata un'applicazione React a pagina singola (SPA) che accede agli utenti e chiama Microsoft Graph usando il flusso di codice di autorizzazione con PKCE. La spa creata usa Microsoft Authentication Library (MSAL) per React.

In questa esercitazione:

  • Creare un progetto di React connpm
  • Registrare l'applicazione nel portale di Azure
  • Aggiungere il codice per supportare l'accesso e la disconnessione
  • Aggiungere il codice per chiamare l'API Microsoft Graph
  • Testare l'app

MSAL React supporta il flusso del codice di autorizzazione nel browser anziché il flusso di concessione implicito. MSAL React 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 una React SPA di eseguire query sull'API Graph Microsoft acquisendo token di sicurezza dall'Microsoft Identity Platform. Usa MSAL per React, un wrapper della libreria MSAL.js v2. MSAL React consente React 16 applicazioni per autenticare gli utenti aziendali usando Azure Active Directory (Azure AD) e anche gli utenti con account Microsoft e identità social come Facebook, Google e LinkedIn. La libreria consente inoltre di ottenere l'accesso a servizi cloud Microsoft e a Microsoft Graph.

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 dei token vengono gestiti da MSAL per React (MSAL React).

Librerie

Questa esercitazione usa le librerie seguenti:

Libreria Descrizione
MSAL React Microsoft Authentication Library per JavaScript React Wrapper
MSAL Browser Pacchetto del browser Microsoft Authentication Library per JavaScript v2

Ottenere l'esempio di codice completo

Si preferisce invece scaricare il progetto di esempio completo di questa esercitazione? Per eseguire il progetto usando un server Web locale, ad esempio Node.js, clonare il repository ms-identity-javascript-react-spa :

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

Quindi, per configurare l'esempio di codice prima di eseguirlo, procedere con 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 installato Node.js , aprire una finestra del terminale e quindi eseguire i comandi seguenti:

npx create-react-app msal-react-tutorial # Create a new React app
cd msal-react-tutorial # Change to the app directory
npm install @azure/msal-browser @azure/msal-react # Install the MSAL packages
npm install react-bootstrap bootstrap # Install Bootstrap for styling

A questo punto è stato eseguito l'avvio di un piccolo progetto di React usando Crea app React. Questo sarà il punto iniziale su cui verrà compilata la parte restante di questa esercitazione. Se si desidera visualizzare le modifiche apportate all'app durante l'esecuzione di questa esercitazione, è possibile eseguire il comando seguente:

npm start

Una finestra del browser deve essere aperta automaticamente all'app. In caso contrario, aprire il browser e passare a http://localhost:3000. Ogni volta che si salva un file con codice aggiornato, la pagina verrà ricaricata in modo da riflettere le modifiche.

Registrare l'applicazione

Seguire la procedura descritta nell'applicazione a pagina singola: registrazione dell'app per creare una registrazione dell'app per la spa usando il portale di Azure.

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 create-react-app servirà l'applicazione.

Configurare JavaScript SPA

  1. Creare un file denominato authConfig.js nella cartella src per contenere i parametri di configurazione per l'autenticazione e quindi aggiungere il codice seguente:

    export const msalConfig = {
      auth: {
        clientId: "Enter_the_Application_Id_Here",
        authority: "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here", // This is a URL (e.g. https://login.microsoftonline.com/{your tenant ID})
        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
      }
    };
    
    // Add scopes here for ID token to be used at Microsoft identity platform endpoints.
    export const loginRequest = {
     scopes: ["User.Read"]
    };
    
    // Add the endpoints here for Microsoft Graph API services you'd like to use.
    export const graphConfig = {
        graphMeEndpoint: "Enter_the_Graph_Endpoint_Here/v1.0/me"
    };
    
  2. Modificare i valori nella sezione msalConfig come descritto di seguito:

    Nome del valore Informazioni
    Enter_the_Application_Id_Here ID applicazione (client) dell'applicazione registrata.
    Enter_the_Cloud_Instance_Id_Here Istanza cloud di Azure in cui viene registrata l'applicazione. Per il cloud principale (o globale) di Azure, immettere https://login.microsoftonline.com. Peri cloud nazionali, ad esempio Cina, è possibile trovare i valori appropriati nella pagina Cloud nazionali.
    Enter_the_Tenant_Info_Here Impostare il valore su una delle opzioni seguenti: Se l'applicazione supporta account in questa directory dell'organizzazione, sostituire questo valore con l'ID della directory (tenant) o il nome del tenant (ad esempio, contoso.microsoft.com). Se l'applicazione supporta Account in qualsiasi directory organizzativa, sostituire questo valore con organizations. Se l'applicazione supporta Account in qualsiasi directory organizzativa e account Microsoft personali, sostituire questo valore con common. Per limitare il supporto ai soli account Microsoft personali, sostituire questo valore con consumers.
    Enter_the_Redirect_Uri_Here Sostituire con http://localhost:3000.
    Enter_the_Graph_Endpoint_Here L'istanza di Microsoft API Graph l'applicazione deve comunicare con. 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.

    Per altre informazioni sulle opzioni configurabili disponibili, vedere Inizializzare le applicazioni client.

  3. Aprire il file src/index.js e aggiungere le importazioni seguenti:

    import "bootstrap/dist/css/bootstrap.min.css";
    import { PublicClientApplication } from "@azure/msal-browser";
    import { MsalProvider } from "@azure/msal-react";
    import { msalConfig } from "./authConfig";
    
  4. Sotto le importazioni in src/index.js creare un'istanza PublicClientApplication usando la configurazione dal passaggio 1.

    const msalInstance = new PublicClientApplication(msalConfig);
    
  5. Trovare il componente in src/index.js e eseguire il <App /> wrapping nel MsalProvider componente. La funzione di rendering dovrebbe essere simile alla seguente:

    ReactDOM.render(
        <React.StrictMode>
            <MsalProvider instance={msalInstance}>
                <App />
            </MsalProvider>
        </React.StrictMode>,
        document.getElementById("root")
    );
    

Consentire l'accesso degli utenti

Creare una cartella in src denominata components e creare un file all'interno di questa cartella denominata SignInButton.jsx. Aggiungere il codice da una delle sezioni seguenti per richiamare l'accesso usando una finestra popup o un reindirizzamento full-frame:

Accedere tramite popup

Aggiungere il codice seguente a src/components/SignInButton.jsx per creare un componente pulsante che richiama un account di accesso popup quando selezionato:

import React from "react";
import { useMsal } from "@azure/msal-react";
import { loginRequest } from "../authConfig";
import Button from "react-bootstrap/Button";

function handleLogin(instance) {
    instance.loginPopup(loginRequest).catch(e => {
        console.error(e);
    });
}

/**
 * Renders a button which, when selected, will open a popup for login
 */
export const SignInButton = () => {
    const { instance } = useMsal();

    return (
        <Button variant="secondary" className="ml-auto" onClick={() => handleLogin(instance)}>Sign in using Popup</Button>
    );
}

Accedere usando i reindirizzamenti

Aggiungere il codice seguente a src/components/SignInButton.jsx per creare un componente pulsante che richiamerà un account di accesso di reindirizzamento quando selezionato:

import React from "react";
import { useMsal } from "@azure/msal-react";
import { loginRequest } from "../authConfig";
import Button from "react-bootstrap/Button";

function handleLogin(instance) {
    instance.loginRedirect(loginRequest).catch(e => {
        console.error(e);
    });
}

/**
 * Renders a button which, when selected, will redirect the page to the login prompt
 */
export const SignInButton = () => {
    const { instance } = useMsal();

    return (
        <Button variant="secondary" className="ml-auto" onClick={() => handleLogin(instance)}>Sign in using Redirect</Button>
    );
}

Aggiungere il pulsante di accesso

  1. Creare un altro file nella cartella dei componenti denominata PageLayout.jsx e aggiungere il codice seguente per creare un componente della barra di spostamento che conterrà il pulsante di accesso appena creato:

    import React from "react";
    import Navbar from "react-bootstrap/Navbar";
    import { useIsAuthenticated } from "@azure/msal-react";
    import { SignInButton } from "./SignInButton";
    
    /**
     * Renders the navbar component with a sign-in button if a user is not authenticated
     */
    export const PageLayout = (props) => {
        const isAuthenticated = useIsAuthenticated();
    
        return (
            <>
                <Navbar bg="primary" variant="dark">
                    <a className="navbar-brand" href="/">MSAL React Tutorial</a>
                    { isAuthenticated ? <span>Signed In</span> : <SignInButton /> }
                </Navbar>
                <h5><center>Welcome to the Microsoft Authentication Library For React Tutorial</center></h5>
                <br />
                <br />
                {props.children}
            </>
        );
    };
    
  2. Aprire ora src/App.js e aggiungere il contenuto esistente con il codice seguente:

    import React from "react";
    import { PageLayout } from "./components/PageLayout";
    
    function App() {
      return (
          <PageLayout>
              <p>This is the main app content!</p>
          </PageLayout>
      );
    }
    
    export default App;
    

L'app ora ha un pulsante di accesso, che viene visualizzato solo per gli utenti non autenticati!

Quando un utente seleziona il pulsante Accedi usando popup o Accedi usando il pulsante Reindirizzamento per la prima volta, il onClick gestore chiama loginPopup (o loginRedirect) per accedere all'utente. 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.

Disconnettersi dagli utenti

In src/components creare un file denominato SignOutButton.jsx. Aggiungere il codice da una delle sezioni seguenti per richiamare l'accesso usando una finestra popup o un reindirizzamento full-frame:

Disconnettersi tramite popup

Aggiungere il codice seguente a src/components/SignOutButton.jsx per creare un componente pulsante che richiama un disconnessione popup quando selezionato:

import React from "react";
import { useMsal } from "@azure/msal-react";
import Button from "react-bootstrap/Button";

function handleLogout(instance) {
    instance.logoutPopup().catch(e => {
        console.error(e);
    });
}

/**
 * Renders a button which, when selected, will open a popup for logout
 */
export const SignOutButton = () => {
    const { instance } = useMsal();

    return (
        <Button variant="secondary" className="ml-auto" onClick={() => handleLogout(instance)}>Sign out using Popup</Button>
    );
}

Disconnettersi usando i reindirizzamenti

Aggiungere il codice seguente a src/components/SignOutButton.jsx per creare un componente pulsante che richiama un disconnessione di reindirizzamento quando selezionato:

import React from "react";
import { useMsal } from "@azure/msal-react";
import Button from "react-bootstrap/Button";

function handleLogout(instance) {
    instance.logoutRedirect().catch(e => {
        console.error(e);
    });
}

/**
 * Renders a button which, when selected, will redirect the page to the logout prompt
 */
export const SignOutButton = () => {
    const { instance } = useMsal();

    return (
        <Button variant="secondary" className="ml-auto" onClick={() => handleLogout(instance)}>Sign out using Redirect</Button>
    );
}

Aggiungere il pulsante di disconnessione

Aggiornare il PageLayout componente in src/components/PageLayout.jsx per eseguire il rendering del nuovo SignOutButton componente per gli utenti autenticati. Il codice dovrebbe essere simile al seguente:

import React from "react";
import Navbar from "react-bootstrap/Navbar";
import { useIsAuthenticated } from "@azure/msal-react";
import { SignInButton } from "./SignInButton";
import { SignOutButton } from "./SignOutButton";

/**
 * Renders the navbar component with a sign-in button if a user is not authenticated
 */
export const PageLayout = (props) => {
    const isAuthenticated = useIsAuthenticated();

    return (
        <>
            <Navbar bg="primary" variant="dark">
                <a className="navbar-brand" href="/">MSAL React Tutorial</a>
                { isAuthenticated ? <SignOutButton /> : <SignInButton /> }
            </Navbar>
            <h5><center>Welcome to the Microsoft Authentication Library For React Tutorial</center></h5>
            <br />
            <br />
            {props.children}
        </>
    );
};

Componenti di rendering condizionale

Per eseguire il rendering di determinati componenti solo per gli utenti autenticati o non autenticati, usare e AuthenticateTemplate /o UnauthenticatedTemplate come illustrato di seguito.

  1. Aggiungere l'importazione seguente a src/App.js:

    import { AuthenticatedTemplate, UnauthenticatedTemplate } from "@azure/msal-react";
    
  2. Per eseguire il rendering di determinati componenti solo per gli utenti autenticati, aggiornare la App funzione in src/App.js con il codice seguente:

    function App() {
        return (
            <PageLayout>
                <AuthenticatedTemplate>
                    <p>You are signed in!</p>
                </AuthenticatedTemplate>
            </PageLayout>
        );
    }
    
  3. Per eseguire il rendering di determinati componenti solo per utenti non autenticati, ad esempio un suggerimento per l'accesso, aggiornare la App funzione in src/App.js con il codice seguente:

    function App() {
        return (
            <PageLayout>
                <AuthenticatedTemplate>
                    <p>You are signed in!</p>
                </AuthenticatedTemplate>
                <UnauthenticatedTemplate>
                    <p>You are not signed in! Please sign in.</p>
                </UnauthenticatedTemplate>
            </PageLayout>
        );
    }
    

Acquisire un token

  1. Prima di chiamare un'API, ad esempio Microsoft Graph, sarà necessario acquisire un token di accesso. Aggiungere un nuovo componente a src/App.js chiamato ProfileContent con il codice seguente:

    function ProfileContent() {
        const { instance, accounts, inProgress } = useMsal();
        const [accessToken, setAccessToken] = useState(null);
    
        const name = accounts[0] && accounts[0].name;
    
        function RequestAccessToken() {
            const request = {
                ...loginRequest,
                account: accounts[0]
            };
    
            // Silently acquires an access token which is then attached to a request for Microsoft Graph data
            instance.acquireTokenSilent(request).then((response) => {
                setAccessToken(response.accessToken);
            }).catch((e) => {
                instance.acquireTokenPopup(request).then((response) => {
                    setAccessToken(response.accessToken);
                });
            });
        }
    
        return (
            <>
                <h5 className="card-title">Welcome {name}</h5>
                {accessToken ? 
                    <p>Access Token Acquired!</p>
                    :
                    <Button variant="secondary" onClick={RequestAccessToken}>Request Access Token</Button>
                }
            </>
        );
    };
    
  2. Aggiornare le importazioni in src/App.js in modo che corrispondano al frammento di codice seguente:

    import React, { useState } from "react";
    import { PageLayout } from "./components/PageLayout";
    import { AuthenticatedTemplate, UnauthenticatedTemplate, useMsal } from "@azure/msal-react";
    import { loginRequest } from "./authConfig";
    import Button from "react-bootstrap/Button";
    
  3. Infine, aggiungere il nuovo ProfileContent componente come figlio del AuthenticatedTemplate componente in Appsrc/App.js. Il App componente dovrebbe essere simile al seguente:

    function App() {
      return (
          <PageLayout>
              <AuthenticatedTemplate>
                  <ProfileContent />
              </AuthenticatedTemplate>
              <UnauthenticatedTemplate>
                  <p>You are not signed in! Please sign in.</p>
              </UnauthenticatedTemplate>
          </PageLayout>
      );
    }
    

Il codice precedente eseguirà il rendering di un pulsante per gli utenti connessi, consentendo loro di richiedere un token di accesso per Microsoft Graph quando viene selezionato il pulsante.

Dopo l'accesso di un utente, l'app non deve chiedere agli utenti di eseguire nuovamente l'autenticazione ogni volta che devono accedere a una risorsa protetta, ovvero per richiedere un token. Per evitare tali richieste di riutenticazione, chiamare acquireTokenSilent che cercherà prima un token di accesso memorizzato nella cache, non scaduto, quindi, se necessario, usare il token di aggiornamento per ottenere un nuovo token di accesso. Esistono tuttavia alcune situazioni in cui potrebbe essere necessario forzare gli utenti a interagire con il Microsoft Identity Platform. Ad esempio:

  • Gli utenti devono immettere nuovamente le credenziali perché la sessione è scaduta.
  • Il token di aggiornamento è scaduto.
  • 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 all'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.

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.

Chiamare l'API Microsoft Graph

  1. Creare un file denominato graph.js nella cartella src e aggiungere il codice seguente per effettuare chiamate REST al API Graph Microsoft:

    import { graphConfig } from "./authConfig";
    
    /**
     * Attaches a given access token to a Microsoft Graph API call. Returns information about the user
     */
    export async function callMsGraph(accessToken) {
        const headers = new Headers();
        const bearer = `Bearer ${accessToken}`;
    
        headers.append("Authorization", bearer);
    
        const options = {
            method: "GET",
            headers: headers
        };
    
        return fetch(graphConfig.graphMeEndpoint, options)
            .then(response => response.json())
            .catch(error => console.log(error));
    }
    
  2. Creare quindi un file denominato ProfileData.jsx in src/components e aggiungere il codice seguente:

    import React from "react";
    
    /**
     * Renders information about the user obtained from Microsoft Graph
     */
    export const ProfileData = (props) => {
        return (
            <div id="profile-div">
                <p><strong>First Name: </strong> {props.graphData.givenName}</p>
                <p><strong>Last Name: </strong> {props.graphData.surname}</p>
                <p><strong>Email: </strong> {props.graphData.userPrincipalName}</p>
                <p><strong>Id: </strong> {props.graphData.id}</p>
            </div>
        );
    };
    
  3. Aprire quindi src/App.js e aggiungere le importazioni seguenti:

    import { ProfileData } from "./components/ProfileData";
    import { callMsGraph } from "./graph";
    
  4. Infine, aggiornare il ProfileContent componente in src/App.js per chiamare Microsoft Graph e visualizzare i dati del profilo dopo aver acquisito il token. Il ProfileContent componente dovrebbe essere simile al seguente:

    function ProfileContent() {
        const { instance, accounts } = useMsal();
        const [graphData, setGraphData] = useState(null);
    
        const name = accounts[0] && accounts[0].name;
    
        function RequestProfileData() {
            const request = {
                ...loginRequest,
                account: accounts[0]
            };
    
            // Silently acquires an access token which is then attached to a request for Microsoft Graph data
            instance.acquireTokenSilent(request).then((response) => {
                callMsGraph(response.accessToken).then(response => setGraphData(response));
            }).catch((e) => {
                instance.acquireTokenPopup(request).then((response) => {
                    callMsGraph(response.accessToken).then(response => setGraphData(response));
                });
            });
        }
    
        return (
            <>
                <h5 className="card-title">Welcome {name}</h5>
                {graphData ? 
                    <ProfileData graphData={graphData} />
                    :
                    <Button variant="secondary" onClick={RequestProfileData}>Request Profile Information</Button>
                }
            </>
        );
    };
    

Nelle modifiche apportate in precedenza, il callMSGraph() metodo viene usato per effettuare una richiesta HTTP GET su 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 e ora è pronta per avviare il server Web e testare la funzionalità dell'app.

  1. Servire l'app eseguendo il comando seguente all'interno della radice della cartella del progetto:

    npm start
    
  2. Una finestra del browser deve essere aperta automaticamente all'app. In caso contrario, aprire il browser e passare a http://localhost:3000. Verrà visualizzata una pagina simile a quella seguente.

    Web browser displaying sign-in dialog

  3. Selezionare il pulsante di accesso per accedere.

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 accettano le autorizzazioni richieste, le applicazioni Web visualizzano il nome, 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 nel portale di Azure. 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.

Guida 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

Se si vuole approfondire lo sviluppo di applicazioni a pagina singola JavaScript con Microsoft Identity Platform, vedere la serie di scenari in più parti: