Hitelesítés engedélyezése saját egyoldalas alkalmazásban Azure AD B2C használatával

Ez a cikk bemutatja, hogyan adhat hozzá Azure Active Directory B2C-hitelesítést (Azure AD B2C) saját egyoldalas alkalmazásához (SPA). Megtudhatja, hogyan hozhat létre SPA-alkalmazást a Microsoft Authentication Library for JavaScript (MSAL.js) használatával.

Ezt a cikket a Hitelesítés konfigurálása egy spa-mintaalkalmazásban című témakörben találja, és a minta SPA-alkalmazást a saját SPA-alkalmazásával helyettesítheti.

Áttekintés

Ez a cikk Node.js és Express használatával hoz létre alapszintű Node.js webalkalmazást. Az Express egy minimális és rugalmas Node.js webalkalmazás-keretrendszer, amely számos funkciót biztosít a web- és mobilalkalmazásokhoz.

A MSAL.js hitelesítési kódtár egy Microsoft által biztosított kódtár, amely leegyszerűsíti a hitelesítés és az engedélyezés támogatását az SPA-alkalmazásokhoz.

Tipp

A teljes MSAL.js kód az ügyféloldalon fut. A Node.js és az Express kiszolgálóoldali kódját más megoldásokkal is helyettesítheti, például a .NET Core, a Java és a Hypertext Preprocessor (PHP) szkriptnyelvekkel.

Előfeltételek

Az előfeltételek és az integrációs utasítások áttekintéséhez lásd: Hitelesítés konfigurálása spa-mintaalkalmazásban.

1. lépés: SPA-alkalmazásprojekt létrehozása

Használhat egy meglévő SPA-alkalmazásprojektet, vagy létrehozhat egy újat. Új projekt létrehozásához tegye a következőket:

  1. Nyisson meg egy parancshéjat, és hozzon létre egy új könyvtárat (például myApp). Ez a könyvtár tartalmazza az alkalmazáskódot, a felhasználói felületet és a konfigurációs fájlokat.

  2. Adja meg a létrehozott könyvtárat.

  3. npm init Az paranccsal hozzon létre egy package.json fájlt az alkalmazáshoz. Ez a parancssor az alkalmazással kapcsolatos információk megadását kéri (például az alkalmazás nevét és verzióját, valamint a kezdeti belépési pont nevét, a index.js fájlt). Futtassa a következő parancsot, és fogadja el az alapértelmezett értékeket:

npm init

2. lépés: A függőségek telepítése

Az Express-csomag telepítéséhez futtassa a következő parancsot a parancshéjban:

npm install express

Az alkalmazás statikus fájljainak megkereséséhez a kiszolgálóoldali kód a Path csomagot használja.

Az Elérési út csomag telepítéséhez futtassa a következő parancsot a parancshéjban:

npm install path

3. lépés: A webkiszolgáló konfigurálása

A myApp mappában hozzon létre egy index.jsnevű fájlt, amely a következő kódot tartalmazza:

// Initialize express
const express = require('express');
const app = express();

// The port to listen to incoming HTTP requests
const port = 6420;

// Initialize path
const path = require('path');

// Set the front-end folder to serve public assets.
app.use(express.static('App'));

// Set up a route for the index.html
app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname + '/index.html'));
});

// Start the server, and listen for HTTP requests
app.listen(port, () => {
  console.log(`Listening on http://localhost:${port}`);
});

4. lépés: Az SPA felhasználói felületének létrehozása

Adja hozzá az SPA-alkalmazásfájlt index.html . Ez a fájl egy Bootstrap-keretrendszerrel létrehozott felhasználói felületet implementál, és szkriptfájlokat importál konfigurációs, hitelesítési és webes API-hívásokhoz.

A index.html fájl által hivatkozott erőforrásokat az alábbi táblázatban találja:

Referencia Definíció
MSAL.js könyvtár MSAL.js hitelesítés JavaScript-kódtár CDN-elérési útja.
Bootstrap stíluslap Ingyenes előtér-keretrendszer a gyorsabb és egyszerűbb webes fejlesztéshez. A keretrendszer HTML- és CSS-alapú tervezési sablonokat tartalmaz.
policies.js A Azure AD B2C egyéni szabályzatait és felhasználói folyamatait tartalmazza.
authConfig.js Hitelesítési konfigurációs paramétereket tartalmaz.
authRedirect.js A hitelesítési logikát tartalmazza.
apiConfig.js Webes API-hatóköröket és az API-végpont helyét tartalmazza.
api.js Meghatározza az API meghívásához és a válasz kezeléséhez használni kívánt módszert.
ui.js Szabályozza a felhasználói felület elemeit.

Az SPA-indexfájl megjelenítéséhez a myApp mappában hozzon létre egy index.htmlnevű fájlt, amely a következő HTML-kódrészletet tartalmazza:

<!DOCTYPE html>
<html>
    <head>
        <title>My Azure AD B2C test app</title>
    </head>
    <body>
        <h2>My Azure AD B2C test app</h2>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />
        <button type="button" id="signIn" class="btn btn-secondary" onclick="signIn()">Sign-in</button>
        <button type="button" id="signOut" class="btn btn-success d-none" onclick="signOut()">Sign-out</button>
        <h5 id="welcome-div" class="card-header text-center d-none"></h5>
        <br />
        <!-- Content -->
        <div class="card">
            <div class="card-body text-center">
                <pre id="response" class="card-text"></pre>
                <button type="button" id="callApiButton" class="btn btn-primary d-none" onclick="passTokenToApi()">Call API</button>
            </div>
        </div>
        <script src="https://alcdn.msauth.net/browser/2.14.2/js/msal-browser.min.js" integrity="sha384-ggh+EF1aSqm+Y4yvv2n17KpurNcZTeYtUZUvhPziElsstmIEubyEB6AIVpKLuZgr" crossorigin="anonymous"></script>

        <!-- Importing app scripts (load order is important) -->
        <script type="text/javascript" src="./apiConfig.js"></script>
        <script type="text/javascript" src="./policies.js"></script>
        <script type="text/javascript" src="./authConfig.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="./authRedirect.js"></script>
        <script type="text/javascript" src="./api.js"></script>
    </body>
</html>

5. lépés: A hitelesítési kódtár konfigurálása

Konfigurálja, hogy a MSAL.js kódtár hogyan integrálható Azure AD B2C-vel. A MSAL.js kódtár egy gyakori konfigurációs objektumot használ a Azure AD B2C-bérlő hitelesítési végpontjaihoz való csatlakozáshoz.

A hitelesítési kódtár konfigurálásához tegye a következőket:

  1. A myApp mappában hozzon létre egy app nevű új mappát.

  2. Az Alkalmazás mappában hozzon létre egy új fájlt authConfig.jsnéven.

  3. Adja hozzá a következő JavaScript-kódot a authConfig.js fájlhoz:

    const msalConfig = {
        auth: {
        clientId: "<Application-ID>", 
        authority: b2cPolicies.authorities.signUpSignIn.authority, 
        knownAuthorities: [b2cPolicies.authorityDomain], 
        redirectUri: "http://localhost:6420",
        },
        cache: {
        cacheLocation: "localStorage", .
        storeAuthStateInCookie: false, 
        }
    };
    
    const loginRequest = {
    scopes: ["openid", ...apiConfig.b2cScopes],
    };
    
    const tokenRequest = {
    scopes: [...apiConfig.b2cScopes],
    forceRefresh: false
    };
    
  4. Cserélje le a elemet <Application-ID> az alkalmazásregisztrációs alkalmazásazonosítóra. További információ: Hitelesítés konfigurálása minta SPA-alkalmazásban.

Tipp

További MSAL-objektumkonfigurációs lehetőségekért tekintse meg a Hitelesítési beállítások című cikket.

6. lépés: A Azure AD B2C felhasználói folyamatainak megadása

Hozza létre a policies.js fájlt, amely információkat nyújt a Azure AD B2C-környezetről. A MSAL.js kódtár ezeket az információkat használja a B2C Azure AD hitelesítési kérések létrehozásához.

A Azure AD B2C felhasználói folyamatainak megadásához tegye a következőket:

  1. Az Alkalmazás mappában hozzon létre egy új fájlt policies.jsnéven.

  2. Adja hozzá a következő kódot a policies.js fájlhoz:

    const b2cPolicies = {
        names: {
            signUpSignIn: "B2C_1_SUSI",
            editProfile: "B2C_1_EditProfile"
        },
        authorities: {
            signUpSignIn: {
                authority: "https://contoso.b2clogin.com/contoso.onmicrosoft.com/Your-B2C-SignInOrSignUp-Policy-Id",
            },
            editProfile: {
                authority: "https://contoso.b2clogin.com/contoso.onmicrosoft.com/Your-B2C-EditProfile-Policy-Id"
            }
        },
        authorityDomain: "contoso.b2clogin.com"
    }
    
  3. Cserélje le a elemet B2C_1_SUSI a bejelentkezési Azure AD B2C-szabályzat nevére.

  4. Cserélje le a elemet B2C_1_EditProfile a szerkesztési profilra Azure AD B2C-szabályzat nevére.

  5. Cserélje le az összes példányt contoso a Azure AD B2C-bérlő nevére.

7. lépés: A felhasználó bejelentkezése az MSAL használatával

Ebben a lépésben implementálja a bejelentkezési folyamat inicializálására szolgáló metódusokat, az API hozzáférési jogkivonat-beszerzését és a kijelentkezési módszereket.

További információ: A Microsoft Authentication Library (MSAL) használata a felhasználói bejelentkezéshez című cikk.

A felhasználó bejelentkezéséhez tegye a következőket:

  1. Az Alkalmazás mappában hozzon létre egy új fájlt authRedirect.jsnéven.

  2. Másolja és illessze be a következő kódot a authRedirect.js:

    // Create the main myMSALObj instance
    // configuration parameters are located at authConfig.js
    const myMSALObj = new msal.PublicClientApplication(msalConfig);
    
    let accountId = "";
    let idTokenObject = "";
    let accessToken = null;
    
    myMSALObj.handleRedirectPromise()
        .then(response => {
            if (response) {
                /**
                 * For the purpose of setting an active account for UI update, we want to consider only the auth response resulting
                 * from SUSI flow. "tfp" claim in the id token tells us the policy (NOTE: legacy policies may use "acr" instead of "tfp").
                 * To learn more about B2C tokens, visit https://learn.microsoft.com/azure/active-directory-b2c/tokens-overview
                 */
                if (response.idTokenClaims['tfp'].toUpperCase() === b2cPolicies.names.signUpSignIn.toUpperCase()) {
                    handleResponse(response);
                }
            }
        })
        .catch(error => {
            console.log(error);
        });
    
    
    function setAccount(account) {
        accountId = account.homeAccountId;
        idTokenObject = account.idTokenClaims;
        myClaims= JSON.stringify(idTokenObject);
        welcomeUser(myClaims);
    }
    
    function selectAccount() {
    
        /**
         * See here for more information 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 < 1) {
            return;
        } else if (currentAccounts.length > 1) {
    
            /**
             * Due to the way MSAL caches account objects, the auth response from initiating a user-flow
             * is cached as a new account, which results in more than one account in the cache. Here we make
             * sure we are selecting the account with homeAccountId that contains the sign-up/sign-in user-flow, 
             * as this is the default flow the user initially signed-in with.
             */
            const accounts = currentAccounts.filter(account =>
                account.homeAccountId.toUpperCase().includes(b2cPolicies.names.signUpSignIn.toUpperCase())
                &&
                account.idTokenClaims.iss.toUpperCase().includes(b2cPolicies.authorityDomain.toUpperCase())
                &&
                account.idTokenClaims.aud === msalConfig.auth.clientId 
                );
    
            if (accounts.length > 1) {
                // localAccountId identifies the entity for which the token asserts information.
                if (accounts.every(account => account.localAccountId === accounts[0].localAccountId)) {
                    // All accounts belong to the same user
                    setAccount(accounts[0]);
                } else {
                    // Multiple users detected. Logout all to be safe.
                    signOut();
                };
            } else if (accounts.length === 1) {
                setAccount(accounts[0]);
            }
    
        } else if (currentAccounts.length === 1) {
            setAccount(currentAccounts[0]);
        }
    }
    
    // in case of page refresh
    selectAccount();
    
    async function handleResponse(response) {
    
        if (response !== null) {
            setAccount(response.account);
        } else {
            selectAccount();
        }
    }
    
    function signIn() {
        myMSALObj.loginRedirect(loginRequest);
    }
    
    function signOut() {
        const logoutRequest = {
            postLogoutRedirectUri: msalConfig.auth.redirectUri,
        };
    
        myMSALObj.logoutRedirect(logoutRequest);
    }
    
    function getTokenRedirect(request) {
        request.account = myMSALObj.getAccountByHomeId(accountId); 
    
        return myMSALObj.acquireTokenSilent(request)
            .then((response) => {
                // In case the response from B2C server has an empty accessToken field
                // throw an error to initiate token acquisition
                if (!response.accessToken || response.accessToken === "") {
                    throw new msal.InteractionRequiredAuthError;
                } else {
                    console.log("access_token acquired at: " + new Date().toString());
                    accessToken = response.accessToken;
                    passTokenToApi();
                }
            }).catch(error => {
                console.log("Silent token acquisition fails. Acquiring token using popup. \n", error);
                if (error instanceof msal.InteractionRequiredAuthError) {
                    // fallback to interaction when silent call fails
                    return myMSALObj.acquireTokenRedirect(request);
                } else {
                    console.log(error);   
                }
        });
    }
    
    // Acquires and access token and then passes it to the API call
    function passTokenToApi() {
        if (!accessToken) {
            getTokenRedirect(tokenRequest);
        } else {
            try {
                callApi(apiConfig.webApi, accessToken);
            } catch(error) {
                console.log(error); 
            }
        }
    }
    
    function editProfile() {
    
    
        const editProfileRequest = b2cPolicies.authorities.editProfile;
        editProfileRequest.loginHint = myMSALObj.getAccountByHomeId(accountId).username;
    
        myMSALObj.loginRedirect(editProfileRequest);
    }
    

8. lépés: A webes API helyének és hatókörének konfigurálása

Ha engedélyezni szeretné, hogy a SPA-alkalmazás meghívjon egy webes API-t, adja meg a webes API-végpont helyét és a webes API-hoz való hozzáférés engedélyezéséhez használni kívánt hatóköröket .

A webes API helyének és hatóköreinek konfigurálásához tegye a következőket:

  1. Az Alkalmazás mappában hozzon létre egy új fájlt apiConfig.jsnéven.

  2. Másolja és illessze be a következő kódot a apiConfig.js:

    // The current application coordinates were pre-registered in a B2C tenant.
    const apiConfig = {
        b2cScopes: ["https://contoso.onmicrosoft.com/tasks/tasks.read"],
        webApi: "https://mydomain.azurewebsites.net/tasks"
    };
    
  3. Cserélje le contoso a elemet a bérlő nevére. A szükséges hatókör neve a Hatókörök konfigurálása című cikkben leírtak szerint található.

  4. Cserélje le a értékét webApi a webes API-végpont helyére.

9. lépés: A webes API meghívása

Adja meg az API-végpontra irányuló HTTP-kérést. A HTTP-kérés úgy van konfigurálva, hogy átadja a MSAL.js által beszerzett hozzáférési jogkivonatot a Authorization kérelem HTTP-fejlécébe.

Az alábbi kód határozza meg a HTTP-kérést GET az API-végpontnak, és átadja a hozzáférési jogkivonatot a Authorization HTTP-fejlécen belül. Az API helyét a webApiapiConfig.jskulcs határozza meg.

Ha a megszerzett jogkivonat használatával szeretné meghívni a webes API-t, tegye a következőket:

  1. Az Alkalmazás mappában hozzon létre egy új fájlt api.jsnéven.

  2. Adja hozzá a következő kódot a api.js fájlhoz:

    function callApi(endpoint, token) {
    
        const headers = new Headers();
        const bearer = `Bearer ${token}`;
    
        headers.append("Authorization", bearer);
    
        const options = {
            method: "GET",
            headers: headers
        };
    
        logMessage('Calling web API...');
    
        fetch(endpoint, options)
        .then(response => response.json())
        .then(response => {
    
            if (response) {
            logMessage('Web API responded: ' + response.name);
            }
    
            return response;
        }).catch(error => {
            console.error(error);
        });
    }
    

10. lépés: A felhasználói felület elemeire vonatkozó referencia hozzáadása

Az SPA alkalmazás JavaScript használatával szabályozza a felhasználói felület elemeit. Megjeleníti például a bejelentkezési és kijelentkezés gombokat, és megjeleníti a felhasználók azonosító jogkivonat-jogcímeit a képernyőn.

A felhasználói felület elemeire vonatkozó hivatkozás hozzáadásához tegye a következőket:

  1. Az Alkalmazás mappában hozzon létre egy ui.jsnevű fájlt.

  2. Adja hozzá a következő kódot a ui.js fájlhoz:

    // Select DOM elements to work with
    const signInButton = document.getElementById('signIn');
    const signOutButton = document.getElementById('signOut')
    const titleDiv = document.getElementById('title-div');
    const welcomeDiv = document.getElementById('welcome-div');
    const tableDiv = document.getElementById('table-div');
    const tableBody = document.getElementById('table-body-div');
    const editProfileButton = document.getElementById('editProfileButton');
    const callApiButton = document.getElementById('callApiButton');
    const response = document.getElementById("response");
    const label = document.getElementById('label');
    
    function welcomeUser(claims) {
        welcomeDiv.innerHTML = `Token claims: </br></br> ${claims}!`
    
        signInButton.classList.add('d-none');
        signOutButton.classList.remove('d-none');
        welcomeDiv.classList.remove('d-none');
        callApiButton.classList.remove('d-none');
    }
    
    function logMessage(s) {
        response.appendChild(document.createTextNode('\n' + s + '\n'));
    }
    

11. lépés: Az SPA-alkalmazás futtatása

Futtassa a következő parancsokat a parancshéjban:

npm install  
npm ./index.js
  1. Nyissa meg a következőt: https://localhost:6420.
  2. Válassza a Bejelentkezés lehetőséget.
  3. Fejezze be a regisztrációt vagy a bejelentkezési folyamatot.

A sikeres hitelesítést követően az elemzési azonosító jogkivonata megjelenik a képernyőn. Válassza ki Call API az API-végpont meghívásához.

Következő lépések