Samouczek: logowanie użytkowników i wywoływanie interfejsu API programu Microsoft Graph z aplikacji jednostronicowej JavaScript (SPA) przy użyciu przepływu kodu uwierzytelniania

W tym samouczku utworzysz jednostronicową aplikację JavaScript (SPA), która loguje użytkowników i wywołuje program Microsoft Graph przy użyciu przepływu kodu autoryzacji za pomocą protokołu PKCE. Utworzone spa używa biblioteki Microsoft Authentication Library (MSAL) dla języka JavaScript w wersji 2.0.

W tym samouczku:

  • Wykonywanie przepływu kodu autoryzacji OAuth 2.0 za pomocą protokołu PKCE
  • Logowanie się do osobistych kont Microsoft, a także kont służbowych
  • Uzyskiwanie tokenu dostępu
  • Wywoływanie programu Microsoft Graph lub własnego interfejsu API wymagającego tokenów dostępu uzyskanych z Platforma tożsamości Microsoft

MSAL.js 2.0 ulepsza MSAL.js 1.0, obsługując przepływ kodu autoryzacji w przeglądarce zamiast niejawnego przepływu udzielania. MSAL.js 2.0 nie obsługuje niejawnego przepływu.

Wymagania wstępne

  • Node.js do uruchamiania lokalnego serwera internetowego
  • Visual Studio Code lub inny edytor kodu

Jak działa aplikacja samouczka

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

Aplikacja utworzona w tym samouczku umożliwia spa języka JavaScript wykonywanie zapytań względem interfejsu API programu Microsoft Graph przez uzyskanie tokenów zabezpieczających z Platforma tożsamości Microsoft. W tym scenariuszu po zalogowaniu użytkownika żąda się tokenu dostępu i jest dodawany do żądań HTTP w nagłówku autoryzacji. Pozyskiwanie i odnawianie tokenów jest obsługiwane przez bibliotekę Microsoft Authentication Library for JavaScript (MSAL.js).

W tym samouczku użyto MSAL.js — pakietu przeglądarki Microsoft Authentication Library for JavaScript w wersji 2.0.

Pobieranie ukończonego przykładu kodu

Zamiast tego możesz pobrać ukończony przykładowy projekt tego samouczka, klonując repozytorium ms-identity-javascript-v2 .

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

Aby uruchomić pobrany projekt w lokalnym środowisku projektowym, zacznij od utworzenia serwera localhost dla aplikacji zgodnie z opisem w kroku 1 tworzenia projektu. Po zakończeniu możesz skonfigurować przykładowy kod, przechodząc do kroku konfiguracji.

Aby kontynuować pracę z samouczkiem i utworzyć aplikację samodzielnie, przejdź do następnej sekcji Utwórz projekt.

Tworzenie projektu

Po zainstalowaniu Node.js utwórz folder do hostowania aplikacji, na przykład msal-spa-tutorial.

Następnie zaimplementuj mały serwer internetowy Express do obsługi pliku index.html .

  1. Najpierw przejdź do katalogu projektu w terminalu, a następnie uruchom następujące npm polecenia:

    npm init -y
    npm install @azure/msal-browser
    npm install express
    npm install morgan
    npm install yargs
    
  2. Następnie utwórz plik o nazwie server.js i dodaj następujący kod:

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

Tworzenie interfejsu użytkownika SPA

  1. Utwórz folder aplikacji w katalogu projektu i w nim utwórz plik index.html dla spa JavaScript. Ten plik implementuje interfejs użytkownika utworzony za pomocą struktury Bootstrap 4 i importuje pliki skryptów na potrzeby konfiguracji, uwierzytelniania i wywołań interfejsu API.

    W pliku index.html dodaj następujący kod:

    <!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. Następnie w folderze aplikacji utwórz plik o nazwie ui.js i dodaj następujący kod. Ten plik będzie uzyskiwać dostęp do elementów DOM i aktualizować je.

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

Rejestrowanie aplikacji

Wykonaj kroki opisane w sekcji Aplikacja jednostronicowa: Rejestracja aplikacji, aby utworzyć rejestrację aplikacji dla spa.

W kroku identyfikatora URI przekierowania: MSAL.js 2.0 z krokiem przepływu kodu uwierzytelniania wprowadź , http://localhost:3000domyślną lokalizację, w której jest uruchomiona aplikacja tego samouczka.

Jeśli chcesz użyć innego portu, wprowadź , http://localhost:<port>gdzie <port> jest preferowanym numerem portu TCP. Jeśli określisz numer portu inny niż 3000, zaktualizuj również server.js przy użyciu preferowanego numeru portu.

Konfigurowanie spa języka JavaScript

Utwórz plik o nazwie authConfig.js w folderze aplikacji , aby zawierał parametry konfiguracji na potrzeby uwierzytelniania, a następnie dodaj następujący kod:

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

Nadal w folderze aplikacji utwórz plik o nazwie graphConfig.js. Dodaj następujący kod, aby udostępnić aplikacji parametry konfiguracji do wywoływania interfejsu API programu 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"
};

Zmodyfikuj wartości w sekcji zgodnie z graphConfig opisem tutaj:

  • Enter_the_Graph_Endpoint_Here to wystąpienie interfejsu API programu Microsoft Graph, z którymi aplikacja powinna się komunikować.
    • W przypadku globalnego punktu końcowego interfejsu API programu Microsoft Graph zastąp oba wystąpienia tego ciągu ciągiem https://graph.microsoft.com.
    • Aby uzyskać informacje o punktach końcowych we wdrożeniach chmury krajowej, zobacz Wdrożenia chmury krajowej w dokumentacji programu Microsoft Graph.

Wartości graphMeEndpoint i graphMailEndpoint w graphConfig.js powinny być podobne do następujących, jeśli używasz globalnego punktu końcowego:

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

Logowanie użytkownika przy użyciu biblioteki Microsoft Authentication Library (MSAL)

Wyskakującego

W folderze aplikacji utwórz plik o nazwie authPopup.js i dodaj następujący kod uwierzytelniania i pozyskiwania tokenu dla wyskakującego okienka logowania:

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

Przekierowanie

Utwórz plik o nazwie authRedirect.js w folderze aplikacji i dodaj następujący kod uwierzytelniania i pozyskiwania tokenu na potrzeby przekierowania logowania:

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

Jak działa kod

Gdy użytkownik wybierze przycisk Zaloguj się po raz pierwszy, signIn metoda wywołuje loginPopup metodę w celu zalogowania się użytkownika. Metoda loginPopup otwiera okno podręczne z punktem końcowym Platforma tożsamości Microsoft w celu wyświetlenia monitu i zweryfikowania poświadczeń użytkownika. Po pomyślnym zalogowaniu msal.js inicjuje przepływ kodu autoryzacji.

W tym momencie kod autoryzacji chroniony przez protokół PKCE jest wysyłany do punktu końcowego tokenu chronionego przez mechanizm CORS i jest wymieniany pod kątem tokenów. Token identyfikatora, token dostępu i token odświeżania są odbierane przez aplikację i przetwarzane przez msal.js, a informacje zawarte w tokenach są buforowane.

Token identyfikatora zawiera podstawowe informacje o użytkowniku, takie jak nazwa wyświetlana. Jeśli planujesz używać jakichkolwiek danych dostarczonych przez token identyfikatora, serwer zaplecza musi zweryfikować go, aby zagwarantować, że token został wystawiony dla prawidłowego użytkownika aplikacji.

Token dostępu ma ograniczony okres istnienia i wygasa po 24 godzinach. Token odświeżania może służyć do dyskretnego uzyskiwania nowych tokenów dostępu.

SPA utworzone w tym samouczku wywołuje acquireTokenSilent i/lub acquireTokenPopup uzyskać token dostępu używany do wykonywania zapytań dotyczących interfejsu API programu Microsoft Graph w celu uzyskania informacji o profilu użytkownika. Jeśli potrzebujesz przykładu sprawdzającego token identyfikatora, zobacz przykładową aplikację active-directory-javascript-singlepageapp-dotnet-webapi-v2 w witrynie GitHub. W przykładzie użyto internetowego interfejsu API ASP.NET do weryfikacji tokenu.

Interaktywne pobieranie tokenu użytkownika

Po początkowym zalogowaniu aplikacja nie powinna prosić użytkowników o ponowne uwierzytelnienie za każdym razem, gdy muszą uzyskać dostęp do chronionego zasobu (czyli zażądać tokenu). Aby zapobiec takim żądaniom ponownego uwierzytelniania, wywołaj metodę acquireTokenSilent. Istnieją jednak pewne sytuacje, w których może być konieczne wymusić na użytkownikach interakcję z Platforma tożsamości Microsoft. Na przykład:

  • Użytkownicy muszą ponownie wprowadzić swoje poświadczenia, ponieważ hasło wygasło.
  • Aplikacja żąda dostępu do zasobu i potrzebujesz zgody użytkownika.
  • Wymagane jest uwierzytelnianie dwuskładnikowe.

Wywołanie acquireTokenPopup otwiera okno podręczne (lub acquireTokenRedirect przekierowuje użytkowników do Platforma tożsamości Microsoft). W tym oknie użytkownicy muszą wchodzić w interakcje, potwierdzając swoje poświadczenia, wyrażając zgodę na wymagany zasób lub kończąc uwierzytelnianie dwuskładnikowe.

Dyskretne pobieranie tokenu użytkownika

Metoda acquireTokenSilent obsługuje pozyskiwanie i odnawianie tokenów bez interakcji z użytkownikiem. Po loginPopup pierwszym acquireTokenSilent wykonaniu (lub loginRedirect) metoda jest często używana do uzyskiwania tokenów używanych do uzyskiwania dostępu do chronionych zasobów na potrzeby kolejnych wywołań. (Wywołania żądań lub odnawiania tokenów są wykonywane w trybie dyskretnym). acquireTokenSilent w niektórych przypadkach może zakończyć się niepowodzeniem. Na przykład hasło użytkownika mogło wygasło. Aplikacja może obsłużyć ten wyjątek na dwa sposoby:

  1. Wywołaj polecenie , aby acquireTokenPopup natychmiast wyzwolić monit logowania użytkownika. Ten wzorzec jest często używany w aplikacjach online, w których nie ma nieuwierzytelnionej zawartości w aplikacji dostępnej dla użytkownika. Przykład wygenerowany przez tę konfigurację z przewodnikiem używa tego wzorca.
  2. Wizualnie wskaż użytkownikowi, że wymagane jest logowanie interakcyjne, aby użytkownik mógł wybrać odpowiedni czas logowania lub aplikacja może ponowić próbę acquireTokenSilent w późniejszym czasie. Ta technika jest często używana, gdy użytkownik może korzystać z innych funkcji aplikacji bez zakłócania działania. Na przykład w aplikacji mogą istnieć nieuwierzytelnione treści. W takiej sytuacji użytkownik może zdecydować, kiedy chce się zalogować, aby uzyskać dostęp do chronionego zasobu, lub odświeżyć nieaktualne informacje.

Uwaga

W tym samouczku domyślnie używane są loginPopup metody i acquireTokenPopup . Jeśli używasz programu Internet Explorer, zalecamy użycie loginRedirect metod i acquireTokenRedirect ze względu na znany problem z programem Internet Explorer i oknami podręcznymi. Aby zapoznać się z przykładem osiągnięcia tego samego wyniku przy użyciu metod przekierowania, zobacz authRedirect.js w witrynie GitHub.

Wywoływanie interfejsu API programu Microsoft Graph

Utwórz plik o nazwie graph.js w folderze aplikacji i dodaj następujący kod do wykonywania wywołań REST do interfejsu API programu 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));
}

W przykładowej aplikacji utworzonej w tym samouczku callMSGraph() metoda służy do tworzenia żądania HTTP GET względem chronionego zasobu, który wymaga tokenu. Następnie żądanie zwraca zawartość do elementu wywołującego. Ta metoda dodaje uzyskany token w nagłówku autoryzacji HTTP. W przykładowej aplikacji utworzonej w tym samouczku chroniony zasób to punkt końcowy interfejsu API me programu Microsoft Graph, który wyświetla informacje o profilu zalogowanego użytkownika.

Testowanie aplikacji

Ukończono tworzenie aplikacji i wszystko jest gotowe do uruchomienia serwera internetowego Node.js i przetestowania funkcjonalności aplikacji.

  1. Uruchom serwer Node.js sieci Web, uruchamiając następujące polecenie z poziomu katalogu głównego folderu projektu:

    npm start
    
  2. W przeglądarce przejdź do http://localhost:3000 adresu lub http://localhost:<port>, gdzie znajduje się port, na którym <port> nasłuchuje serwer internetowy. Powinna zostać wyświetlona zawartość pliku index.html i przycisk Zaloguj się .

Logowanie się do aplikacji

Po załadowaniu pliku index.html przeglądarki wybierz pozycję Zaloguj. Zostanie wyświetlony monit o zalogowanie się przy użyciu Platforma tożsamości Microsoft:

Web browser displaying sign-in dialog

Po pierwszym zalogowaniu się do aplikacji zostanie wyświetlony monit o udzielenie mu dostępu do profilu i zalogowanie się:

Content dialog displayed in web browser

Jeśli wyrazisz zgodę na żądane uprawnienia, aplikacja internetowa wyświetli nazwę użytkownika, co oznacza pomyślne zalogowanie:

Results of a successful sign-in in the web browser

Wywoływanie interfejsu API programu Graph

Po zalogowaniu wybierz pozycję Zobacz profil , aby wyświetlić informacje o profilu użytkownika zwrócone w odpowiedzi z wywołania interfejsu API programu Microsoft Graph:

Profile information from Microsoft Graph displayed in the browser

Więcej informacji o zakresach i uprawnieniach delegowanych

Interfejs API programu Microsoft Graph wymaga zakresu user.read w celu odczytania profilu użytkownika. Domyślnie ten zakres jest automatycznie dodawany w każdej aplikacji zarejestrowanej w centrum administracyjnym firmy Microsoft Entra. Inne interfejsy API dla programu Microsoft Graph, a także niestandardowe interfejsy API dla serwera zaplecza, mogą wymagać dodatkowych zakresów. Na przykład interfejs API programu Microsoft Graph wymaga zakresu Mail.Read , aby wyświetlić listę wiadomości e-mail użytkownika.

Podczas dodawania zakresów użytkownicy mogą być monitowani o udzielenie dodatkowej zgody dla dodanych zakresów.

Jeśli interfejs API zaplecza nie wymaga zakresu, który nie jest zalecany, możesz użyć clientId go jako zakresu w wywołaniach w celu uzyskania tokenów.

Pomoc i obsługa techniczna 

Jeśli potrzebujesz pomocy, chcesz zgłosić problem lub poznać opcje pomocy technicznej, zobacz Pomoc i obsługa techniczna dla deweloperów.

Następne kroki