Dela via


Aktivera autentisering i ditt eget ensidesprogram med hjälp av Azure AD B2C

Den här artikeln visar hur du lägger till Azure Active Directory B2C-autentisering (Azure AD B2C) i ditt eget ensidesprogram (SPA). Lär dig hur du skapar ett SPA-program med hjälp av Microsoft Authentication Library for JavaScript (MSAL.js).

Använd den här artikeln med Konfigurera autentisering i ett spa-exempelprogram och ersätt SPA-exempelappen med din egen SPA-app.

Översikt

Den här artikeln använder Node.js och Express för att skapa en grundläggande Node.js webbapp. Express är ett minimalt och flexibelt Node.js webbappsramverk som tillhandahåller en uppsättning funktioner för webb- och mobilappar.

MSAL.js-autentiseringsbiblioteket är ett bibliotek från Microsoft som gör det enklare att lägga till stöd för autentisering och auktorisering i SPA-appar.

Tips

Hela MSAL.js-koden körs på klientsidan. Du kan ersätta koden för Node.js och Express-serversidan med andra lösningar, till exempel skriptspråken .NET Core, Java och PHP (Hypertext Preprocessor).

Förutsättningar

Mer information om krav och integreringsanvisningar finns i Konfigurera autentisering i ett SPA-exempelprogram.

Steg 1: Skapa ett SPA-appprojekt

Du kan använda ett befintligt SPA-appprojekt eller skapa ett nytt. Om du vill skapa ett nytt projekt gör du följande:

  1. Öppna ett kommandogränssnitt och skapa en ny katalog (till exempel myApp). Den här katalogen innehåller appkoden, användargränssnittet och konfigurationsfilerna.

  2. Ange den katalog som du skapade.

  3. npm init Använd kommandot för att skapa en package.json fil för din app. Det här kommandot uppmanar dig att ange information om din app (till exempel namnet och versionen av din app och namnet på den första startpunkten, index.js-filen ). Kör följande kommando och acceptera standardvärdena:

npm init

Steg 2: Installera beroendena

Installera Express-paketet genom att köra följande kommando i kommandogränssnittet:

npm install express

För att hitta appens statiska filer använder koden på serversidan path-paketet .

Installera path-paketet genom att köra följande kommando i kommandogränssnittet:

npm install path

Steg 3: Konfigurera webbservern

I mappen myApp skapar du en fil med namnet index.js, som innehåller följande kod:

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

Steg 4: Skapa SPA-användargränssnittet

Lägg till SPA-appfilen index.html . Den här filen implementerar ett användargränssnitt som har skapats med ett Bootstrap-ramverk och importerar skriptfiler för konfigurations-, autentiserings- och webb-API-anrop.

De resurser som refereras av index.html-filen beskrivs i följande tabell:

Referens Definition
MSAL.js bibliotek MSAL.js autentisering av JavaScript-bibliotekets CDN-sökväg.
Bootstrap-formatmall Ett kostnadsfritt klientramverk för snabbare och enklare webbutveckling. Ramverket innehåller HTML-baserade och CSS-baserade designmallar.
policies.js Innehåller Azure AD anpassade B2C-principer och användarflöden.
authConfig.js Innehåller konfigurationsparametrar för autentisering.
authRedirect.js Innehåller autentiseringslogik.
apiConfig.js Innehåller webb-API-omfång och API-slutpunktsplatsen.
api.js Definierar vilken metod som ska användas för att anropa ditt API och hantera dess svar.
ui.js Styr gränssnittselementen.

Om du vill rendera SPA-indexfilen skapar du i mappen myApp en fil med namnet index.html, som innehåller följande HTML-kodfragment:

<!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>

Steg 5: Konfigurera autentiseringsbiblioteket

Konfigurera hur MSAL.js-biblioteket integreras med Azure AD B2C. MSAL.js-biblioteket använder ett gemensamt konfigurationsobjekt för att ansluta till din Azure AD B2C-klientorganisationens autentiseringsslutpunkter.

Så här konfigurerar du autentiseringsbiblioteket:

  1. I mappen myApp skapar du en ny mapp med namnet App.

  2. I mappen App skapar du en ny fil med namnet authConfig.js.

  3. Lägg till följande JavaScript-kod i authConfig.js-filen :

    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. Ersätt <Application-ID> med ditt program-ID för appregistrering. Mer information finns i Konfigurera autentisering i ett SPA-exempelprogram.

Tips

Fler konfigurationsalternativ för MSAL-objekt finns i artikeln Autentiseringsalternativ .

Steg 6: Ange dina Azure AD B2C-användarflöden

Skapa policies.js-filen som innehåller information om din Azure AD B2C-miljö. MSAL.js-biblioteket använder den här informationen för att skapa autentiseringsbegäranden för att Azure AD B2C.

Gör följande för att ange dina Azure AD B2C-användarflöden:

  1. I mappen App skapar du en ny fil med namnet policies.js.

  2. Lägg till följande kod i policies.js-filen :

    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. Ersätt B2C_1_SUSI med inloggningsnamnet Azure AD B2C-princip.

  4. Ersätt B2C_1_EditProfile med redigeringsprofilen Azure AD B2C-principnamnet.

  5. Ersätt alla instanser av contoso med ditt Azure AD B2C-klientnamn.

Steg 7: Använd MSAL för att logga in användaren

I det här steget implementerar du metoderna för att initiera inloggningsflödet, hämtning av API-åtkomsttoken och utloggningsmetoderna.

Mer information finns i artikeln Använda Microsoft Authentication Library (MSAL) för att logga in på användaren .

Logga in användaren genom att göra följande:

  1. I mappen App skapar du en ny fil med namnet authRedirect.js.

  2. I authRedirect.jskopierar du och klistrar in följande kod:

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

Steg 8: Konfigurera platsen och omfånget för webb-API:et

Om du vill tillåta att din SPA-app anropar ett webb-API anger du platsen för webb-API:ets slutpunkt och de omfång som ska användas för att auktorisera åtkomst till webb-API:et.

Så här konfigurerar du platsen och omfången för webb-API:et:

  1. I mappen App skapar du en ny fil med namnet apiConfig.js.

  2. I apiConfig.jskopierar du och klistrar in följande kod:

    // 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. Ersätt contoso med ditt klientnamn. Det nödvändiga omfångsnamnet finns enligt beskrivningen i artikeln Konfigurera omfång .

  4. Ersätt värdet för med slutpunktsplatsen för webApi webb-API:et.

Steg 9: Anropa ditt webb-API

Definiera HTTP-begäran till API-slutpunkten. HTTP-begäran har konfigurerats för att skicka den åtkomsttoken som hämtades med MSAL.js till Authorization HTTP-huvudet i begäran.

Följande kod definierar HTTP-begäran till API-slutpunkten GET och skickar åtkomsttoken i Authorization HTTP-huvudet. API-platsen definieras av webApi nyckeln i apiConfig.js.

Om du vill anropa webb-API:et med hjälp av den token som du har köpt gör du följande:

  1. I mappen App skapar du en ny fil med namnet api.js.

  2. Lägg till följande kod i api.js-filen :

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

Steg 10: Lägg till referensen för gränssnittselement

SPA-appen använder JavaScript för att styra gränssnittselementen. Den visar till exempel inloggnings- och utloggningsknapparna och återger användarnas ID-tokenanspråk på skärmen.

Om du vill lägga till referensen för gränssnittselement gör du följande:

  1. I mappen App skapar du en fil med namnet ui.js.

  2. Lägg till följande kod i ui.js-filen :

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

Steg 11: Kör spa-programmet

Kör följande kommandon i kommandogränssnittet:

npm install  
npm ./index.js
  1. Gå till https://localhost:6420.
  2. Välj Logga in.
  3. Slutför registreringen eller inloggningsprocessen.

När du har autentiserats visas den parsade ID-token på skärmen. Välj Call API för att anropa API-slutpunkten.

Nästa steg