JavaScript-alkalmazás migrálása az ADAL.js-ből az MSAL.js-be

A JavaScripthez készült Microsoft Authentication Library (MSAL.js, más néven msal-browser) 2.x az a hitelesítési kódtár, amelyet javaScript-alkalmazásokkal ajánlott használni a Microsoft Identitásplatform. Ez a cikk az ADAL.js-t az MSAL.js 2.x-et használó alkalmazások migrálásához szükséges módosításokat emeli ki.

Megjegyzés:

Erősen ajánljuk az MSAL.js 2.x-et az MSAL.js 1.x-en keresztül. A hitelesítési kód megadásának folyamata biztonságosabb, és lehetővé teszi az egyoldalas alkalmazások számára a jó felhasználói élmény fenntartását annak ellenére, hogy a Safarihoz hasonló adatvédelmi intézkedésekkel többek között letiltják a harmadik féltől származó cookie-kat.

Előfeltételek

  • A platform / válasz URL-címét egyoldalas alkalmazásrakell állítania az alkalmazásregisztrációs portálon (ha más platformokat is hozzáad az alkalmazásregisztrációhoz, például a webet, meg kell győződnie arról, hogy az átirányítási URI-k nem fedik egymást. Lásd: Átirányítási URI-korlátozások)
  • Az alkalmazások Internet Explorerben való futtatásához olyan ES6-funkciókat kell megadnia, amelyekre az MSAL.js támaszkodik (például ígéreteket)
  • Ha még nem tette meg, migrálja a Microsoft Entra-alkalmazásokat a v2-végpontra

MSAL telepítése és importálása

Az MSAL.js 2.x kódtár kétféleképpen telepíthető:

Npm-en keresztül:

npm install @azure/msal-browser

Ezután a modulrendszertől függően importálja az alábbiak szerint:

import * as msal from "@azure/msal-browser"; // ESM

const msal = require('@azure/msal-browser'); // CommonJS

CDN-en keresztül:

Töltse be a szkriptet a HTML-dokumentum fejlécszakaszában:

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="https://alcdn.msauth.net/browser/2.14.2/js/msal-browser.min.js"></script>
  </head>
</html>

A CDN használatakor használható alternatív CDN-hivatkozások és ajánlott eljárások: CDN-használat

MSAL inicializálása

Az ADAL.js-ben példányosíthatja az AuthenticationContext osztályt, amely ezután elérhetővé teszi a hitelesítés (loginacquireTokenPopupstb.) eléréséhez használható módszereket. Ez az objektum az alkalmazás engedélyezési kiszolgálóval vagy identitásszolgáltatóval való kapcsolatának ábrázolására szolgál. Inicializáláskor az egyetlen kötelező paraméter a clientId:

window.config = {
  clientId: "YOUR_CLIENT_ID"
};

var authContext = new AuthenticationContext(config);

Az MSAL.js-ben ehelyett a PublicClientApplication osztályt példányosíthatja. Az ADAL.js-hez hasonlóan a konstruktor egy olyan konfigurációs objektumot vár, amely legalább a clientId paramétert tartalmazza. További információ: MSAL.js inicializálása

const msalConfig = {
  auth: {
      clientId: 'YOUR_CLIENT_ID'
  }
};

const msalInstance = new msal.PublicClientApplication(msalConfig);

Az ADAL.js és az MSAL.js esetén a szolgáltatói URI alapértelmezés szerint https://login.microsoftonline.com/common az, ha nem adja meg.

Megjegyzés:

Ha a szolgáltatót a https://login.microsoftonline.com/common 2.0-s verzióban használja, engedélyezi a felhasználóknak, hogy bármilyen Microsoft Entra-szervezettel vagy személyes Microsoft-fiókkal (MSA) jelentkezzenek be. Ha az MSAL.js-ben korlátozni szeretné a bejelentkezést bármely Microsoft Entra-fiókra (ugyanaz a viselkedés, mint az ADAL.js esetén), használja https://login.microsoftonline.com/organizations helyette.

MSAL konfigurálása

Az ADAL.js-ben az AuthenticationContext inicializálásakor használt konfigurációs beállítások némelyike elavult az MSAL.js-ben, míg egyes újak bevezetésre kerülnek. Tekintse meg az elérhető lehetőségek teljes listáját. Fontos, hogy a jogkivonatok beszerzése során ezen lehetőségek clientIdközül sok felül is bírálható, így kérésenként állíthatja be őket. Használhat például egy másik szolgáltatói URI-t vagy átirányítási URI-t , mint amelyet az inicializálás során állított be a jogkivonatok beszerzésekor.

Emellett már nem kell megadnia a bejelentkezési felületet (azaz az előugró ablakok használatát vagy az oldal átirányítását) a konfigurációs beállításokon keresztül. MSAL.js Ehelyett tegye elérhetővé és loginRedirect metódusokat loginPopup a PublicClientApplication példányon keresztül.

Naplózás engedélyezése

Az ADAL.js-ben a naplózást a kód bármely helyére külön konfigurálhatja:

window.config = {
  clientId: "YOUR_CLIENT_ID"
};

var authContext = new AuthenticationContext(config);

var Logging = {
  level: 3,
  log: function (message) {
      console.log(message);
  },
  piiLoggingEnabled: false
};


authContext.log(Logging)

Az MSAL.js-ben a naplózás a konfigurációs beállítások része, és a következő inicializálása PublicClientApplicationsorán jön létre:

const msalConfig = {
  auth: {
      // authentication related parameters
  },
  cache: {
      // cache related parameters
  },
  system: {
      loggerOptions: {
          loggerCallback(loglevel, message, containsPii) {
              console.log(message);
          },
          piiLoggingEnabled: false,
          logLevel: msal.LogLevel.Verbose,
      }
  }
}

const msalInstance = new msal.PublicClientApplication(msalConfig);

Váltás MSAL API-ra

Az ADAL.js nyilvános metódusainak némelyike egyenértékű az MSAL.js-ben:

ADAL MSAL Jegyzetek
acquireToken acquireTokenSilent Átnevezve, és most egy fiókobjektumot vár
acquireTokenPopup acquireTokenPopup Most aszinkron, és visszaad egy ígéretet
acquireTokenRedirect acquireTokenRedirect Most aszinkron, és visszaad egy ígéretet
handleWindowCallback handleRedirectPromise Átirányítási felület használata esetén szükséges
getCachedUser getAllAccounts Átnevezve, és most egy fióktömböt ad vissza.

Mások elavultak, míg az MSAL.js új módszereket kínál:

ADAL MSAL Jegyzetek
login N/A Elavult. Használat loginPopup vagy loginRedirect
logOut N/A Elavult. Használat logoutPopup vagy logoutRedirect
N.A. loginPopup
N/A loginRedirect
N/A logoutPopup
N/A logoutRedirect
N.A. getAccountByHomeId A fiókok szűrése otthoni azonosító alapján (oid + bérlőazonosító)
N/A getAccountLocalId A fiókok szűrése helyi azonosító alapján (az ADFS esetében hasznos)
N/A getAccountUsername Fiókok szűrése felhasználónév alapján (ha létezik)

Emellett mivel az MSAL.js typeScriptben implementálva van az ADAL.js-sel ellentétben, számos különböző típust és felületet tesz elérhetővé, amelyeket a projektekben használhat. További információért tekintse meg az MSAL.js API-referenciát .

Hatókörök használata erőforrások helyett

Az Azure Active Directory 1.0-s és 2.0-s végpontok közötti fontos különbség az erőforrások elérésének módjában van. Ha az ADAL.js-t az 1.0-s verziójú végponttal használja, először regisztráljon egy engedélyt az alkalmazásregisztrációs portálon, majd kérjen hozzáférési jogkivonatot egy erőforráshoz (például a Microsoft Graphhoz) az alábbiak szerint:

authContext.acquireTokenRedirect("https://graph.microsoft.com", function (error, token) {
  // do something with the access token
});

Az MSAL.js csak a 2.0-s verziójú végpontot támogatja. A 2.0-s verziójú végpont hatókör-központú modellt alkalmaz az erőforrások eléréséhez. Így amikor hozzáférési jogkivonatot kér egy erőforráshoz, meg kell adnia az erőforrás hatókörét is:

msalInstance.acquireTokenRedirect({
  scopes: ["https://graph.microsoft.com/User.Read"]
});

A hatókör-központú modell egyik előnye a dinamikus hatókörök használatának képessége. Az 1.0-s verziójú végpontot használó alkalmazások létrehozásakor regisztrálnia kellett az alkalmazás által a bejelentkezéskor hozzájáruláshoz szükséges engedélyek teljes készletét (úgynevezett statikus hatóköröket). A 2.0-s verzióban a hatókör paraméterrel kérheti le az engedélyeket a kívánt időpontban (tehát dinamikus hatókörök). Ez lehetővé teszi, hogy a felhasználó növekményes hozzájárulást adjon a hatókörökhöz. Ha tehát az elején csak azt szeretné, hogy a felhasználó jelentkezzen be az alkalmazásba, és nincs szüksége semmilyen hozzáférésre, megteheti. Ha később szüksége van a felhasználó naptárának olvasására, akkor kérheti a naptár hatókörét a acquireToken metódusokban, és lekérheti a felhasználó hozzájárulását. További információ: Erőforrások és hatókörök

Ígéretek használata visszahívások helyett

Az ADAL.js-ben a rendszer visszahívásokat használ minden művelethez, miután a hitelesítés sikeres volt, és a rendszer választ kapott:

authContext.acquireTokenPopup(resource, extraQueryParameter, claims, function (error, token) {
  // do something with the access token
});

Az MSAL.js-ben az ígéretek a következők:

msalInstance.acquireTokenPopup({
      scopes: ["User.Read"] // shorthand for https://graph.microsoft.com/User.Read
  }).then((response) => {
      // do something with the auth response
  }).catch((error) => {
      // handle errors
  });

Az ES8-hoz kapcsolódó aszinkron/várakozási szintaxist is használhatja:

const getAccessToken = async() => {
  try {
      const authResponse = await msalInstance.acquireTokenPopup({
          scopes: ["User.Read"]
      });
  } catch (error) {
      // handle errors
  }
}

Jogkivonatok gyorsítótárazása és lekérése

Az ADAL.js-hez hasonlóan az MSAL.js gyorsítótárazza a jogkivonatokat és más hitelesítési összetevőket a böngészőtárolóban a Web Storage API használatával. Javasoljuk, hogy használja sessionStorage a lehetőséget (lásd: konfiguráció), mert biztonságosabb a felhasználók által beszerzett jogkivonatok tárolása, de localStorage Egyszeri bejelentkezés biztosít a lapok és a felhasználói munkamenetek között.

Fontos, hogy nem szabad közvetlenül hozzáférnie a gyorsítótárhoz. Ehelyett egy megfelelő MSAL.js API-t kell használnia a hitelesítési összetevők, például hozzáférési jogkivonatok vagy felhasználói fiókok lekéréséhez.

Jogkivonatok megújítása frissítési jogkivonatokkal

Az ADAL.js az OAuth 2.0 implicit folyamatot használja, amely biztonsági okokból nem ad vissza frissítési jogkivonatokat (a frissítési jogkivonatok élettartama hosszabb, mint a hozzáférési jogkivonatoké, ezért veszélyesebbek a rosszindulatú szereplők kezében). Ezért az ADAL.js egy rejtett IFrame használatával hajtja végre a jogkivonat megújítását, hogy a felhasználót ne kelljen ismételten hitelesítésre kérnie.

A PKCE-támogatással rendelkező hitelesítési kódfolyamattal az MSAL.js 2.x-et használó alkalmazások frissítési jogkivonatokat, valamint azonosítókat és hozzáférési jogkivonatokat szereznek be, amelyekkel megújíthatók. A frissítési jogkivonatok használata elvont, és a fejlesztőknek nem szabad logikát építeniük köréjük. Az MSAL ehelyett a frissítési jogkivonatok használatával kezeli a jogkivonatok megújítását. Az ADAL.js-sel rendelkező korábbi tokengyorsítótár nem lesz átadható az MSAL.js-nek, mivel a tokengyorsítótár-séma módosult, és nem kompatibilis az ADAL.js-ben használt sémával.

Hibák és kivételek kezelése

Az MSAL.js használatakor a leggyakoribb hibatípus a interaction_in_progress hiba. Ez a hiba akkor jelentkezik, ha egy interaktív API (loginPopup, loginRedirect, , acquireTokenPopupacquireTokenRedirect) meghívása közben egy másik interaktív API is folyamatban van. Az login* és acquireToken* AZ API-k aszinkronok, ezért gondoskodnia kell arról, hogy az eredményül kapott ígéretek feloldódjanak, mielőtt egy másikat invokált volna.

Egy másik gyakori hiba a .interaction_required Ezt a hibát gyakran egy interaktív jogkivonat-beszerzési kérés kezdeményezésével oldják meg. Előfordulhat például, hogy a elérni kívánt webes API feltételes hozzáférési szabályzattal rendelkezik, amely megköveteli, hogy a felhasználó többtényezős hitelesítést (MFA) végezzen. Ebben az esetben a hiba kezelése interaction_required a felhasználó MFA-jának aktiválásával acquireTokenPopup vagy acquireTokenRedirect kérésével, amely lehetővé teszi számukra a teljes beszűkítést.

Egy másik gyakori hiba consent_required, amely akkor fordulhat elő, ha a felhasználó nem engedélyezi a védett erőforrások hozzáférési jogkivonatának beszerzéséhez szükséges engedélyeket. interaction_requiredA hiba megoldásához hasonlóan a hiba megoldása consent_required gyakran egy interaktív jogkivonat beszerzésére irányuló kérést kezdeményez vagy használ acquireTokenPopupacquireTokenRedirect.

További információ: Gyakori MSAL.js-hibák és azok kezelése

Az Események API használata

Az MSAL.js (>=v2.4) egy esemény API-t vezet be, amelyet az alkalmazásokban használhat. Ezek az események a hitelesítési folyamathoz és az MSAL által végzett műveletekhez kapcsolódnak, és felhasználhatók a felhasználói felület frissítésére, a hibaüzenetek megjelenítésére, annak ellenőrzésére, hogy folyamatban van-e bármilyen interakció, és így tovább. Az alábbi eseményvisszahívás például akkor lesz meghívva, ha a bejelentkezési folyamat bármilyen okból meghiúsul:

const callbackId = msalInstance.addEventCallback((message) => {
  // Update UI or interact with EventMessage here
  if (message.eventType === EventType.LOGIN_FAILURE) {
      if (message.error instanceof AuthError) {
          // Do something with the error
      }
    }
});

A teljesítmény szempontjából fontos, hogy törölje az eseményvisszahívások regisztrációját, ha már nincs rájuk szükség. További információ: MSAL.js Events API

Több fiók kezelése

Az ADAL.js egy felhasználó koncepciója, amely a jelenleg hitelesített entitást képviseli. Az MSAL.js a felhasználókat fiókokra cseréli, mivel egy felhasználóhoz több fiók is társítható. Ez azt is jelenti, hogy most már több fiókot is szabályoznia kell, és ki kell választania a megfelelőt, amellyel dolgozhat. Az alábbi kódrészlet a következő folyamatot szemlélteti:

let homeAccountId = null; // Initialize global accountId (can also be localAccountId or username) used for account lookup later, ideally stored in app state

// This callback is passed into `acquireTokenPopup` and `acquireTokenRedirect` to handle the interactive auth response
function handleResponse(resp) {
  if (resp !== null) {
      homeAccountId = resp.account.homeAccountId; // alternatively: resp.account.homeAccountId or resp.account.username
  } else {
      const currentAccounts = myMSALObj.getAllAccounts();
      if (currentAccounts.length < 1) { // No cached accounts
          return;
      } else if (currentAccounts.length > 1) { // Multiple account scenario
          // Add account selection logic here
      } else if (currentAccounts.length === 1) {
          homeAccountId = currentAccounts[0].homeAccountId; // Single account scenario
      }
  }
}

További információ: Fiókok az MSAL.js-ben

A burkolótárak használata

Ha Angular- és React-keretrendszerekhez fejleszt, használhatja az MSAL Angular v2-t és az MSAL Reactet. Ezek a burkolók ugyanazt a nyilvános API-t teszik elérhetővé, mint az MSAL.js, miközben keretrendszerspecifikus metódusokat és összetevőket kínálnak, amelyek egyszerűsíthetik a hitelesítési és jogkivonat-beszerzési folyamatokat.

Az alkalmazás futtatása

A módosítások végrehajtása után futtassa az alkalmazást, és tesztelje a hitelesítési forgatókönyvet:

npm start

Példa: SPA biztonságossá tétele az ADAL.js és az MSAL.js használatával

Az alábbi kódrészletek azt a minimális kódot mutatják be, amely szükséges ahhoz, hogy egy egyoldalas alkalmazás hitelesíthesse a felhasználókat a Microsoft Identitásplatform, és hogy az első ADAL.js, majd MSAL.js használatával hozzáférési jogkivonatot kapjon a Microsoft Graphhoz:

Az ADAL.js használata Az MSAL.js használata

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="https://alcdn.msauth.net/lib/1.0.18/js/adal.min.js"></script>
</head>

<body>
    <div>
        <p id="welcomeMessage" style="visibility: hidden;"></p>
        <button id="loginButton">Login</button>
        <button id="logoutButton" style="visibility: hidden;">Logout</button>
        <button id="tokenButton" style="visibility: hidden;">Get Token</button>
    </div>
    <script>
        // DOM elements to work with
        var welcomeMessage = document.getElementById("welcomeMessage");
        var loginButton = document.getElementById("loginButton");
        var logoutButton = document.getElementById("logoutButton");
        var tokenButton = document.getElementById("tokenButton");

        // if user is logged in, update the UI
        function updateUI(user) {
            if (!user) {
                return;
            }

            welcomeMessage.innerHTML = 'Hello ' + user.profile.upn + '!';
            welcomeMessage.style.visibility = "visible";
            logoutButton.style.visibility = "visible";
            tokenButton.style.visibility = "visible";
            loginButton.style.visibility = "hidden";
        };

        // attach logger configuration to window
        window.Logging = {
            piiLoggingEnabled: false,
            level: 3,
            log: function (message) {
                console.log(message);
            }
        };

        // ADAL configuration
        var adalConfig = {
            instance: 'https://login.microsoftonline.com/',
            clientId: "ENTER_CLIENT_ID_HERE",
            tenant: "ENTER_TENANT_ID_HERE",
            redirectUri: "ENTER_REDIRECT_URI_HERE",
            cacheLocation: "sessionStorage",
            popUp: true,
            callback: function (errorDesc, token, error, tokenType) {
                if (error) {
                    console.log(error, errorDesc);
                } else {
                    updateUI(authContext.getCachedUser());
                }
            }
        };

        // instantiate ADAL client object
        var authContext = new AuthenticationContext(adalConfig);

        // handle redirect response or check for cached user
        if (authContext.isCallback(window.location.hash)) {
            authContext.handleWindowCallback();
        } else {
            updateUI(authContext.getCachedUser());
        }

        // attach event handlers to button clicks
        loginButton.addEventListener('click', function () {
            authContext.login();
        });

        logoutButton.addEventListener('click', function () {
            authContext.logOut();
        });

        tokenButton.addEventListener('click', () => {
            authContext.acquireToken(
                "https://graph.microsoft.com",
                function (errorDesc, token, error) {
                    if (error) {
                        console.log(error, errorDesc);

                        authContext.acquireTokenPopup(
                            "https://graph.microsoft.com",
                            null, // extraQueryParameters
                            null, // claims
                            function (errorDesc, token, error) {
                                if (error) {
                                    console.log(error, errorDesc);
                                } else {
                                    console.log(token);
                                }
                            }
                        );
                    } else {
                        console.log(token);
                    }
                }
            );
        });
    </script>
</body>

</html>


<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="https://alcdn.msauth.net/browser/2.34.0/js/msal-browser.min.js"></script>
</head>

<body>
    <div>
        <p id="welcomeMessage" style="visibility: hidden;"></p>
        <button id="loginButton">Login</button>
        <button id="logoutButton" style="visibility: hidden;">Logout</button>
        <button id="tokenButton" style="visibility: hidden;">Get Token</button>
    </div>
    <script>
        // DOM elements to work with
        const welcomeMessage = document.getElementById("welcomeMessage");
        const loginButton = document.getElementById("loginButton");
        const logoutButton = document.getElementById("logoutButton");
        const tokenButton = document.getElementById("tokenButton");

        // if user is logged in, update the UI
        const updateUI = (account) => {
            if (!account) {
                return;
            }

            welcomeMessage.innerHTML = `Hello ${account.username}!`;
            welcomeMessage.style.visibility = "visible";
            logoutButton.style.visibility = "visible";
            tokenButton.style.visibility = "visible";
            loginButton.style.visibility = "hidden";
        };

        // MSAL configuration
        const msalConfig = {
            auth: {
                clientId: "ENTER_CLIENT_ID_HERE",
                authority: "https://login.microsoftonline.com/ENTER_TENANT_ID_HERE",
                redirectUri: "ENTER_REDIRECT_URI_HERE",
            },
            cache: {
                cacheLocation: "sessionStorage"
            },
            system: {
                loggerOptions: {
                    loggerCallback(loglevel, message, containsPii) {
                        console.log(message);
                    },
                    piiLoggingEnabled: false,
                    logLevel: msal.LogLevel.Verbose,
                }
            }
        };

        // instantiate MSAL client object
        const pca = new msal.PublicClientApplication(msalConfig);

        // handle redirect response or check for cached user
        pca.handleRedirectPromise().then((response) => {
            if (response) {
                pca.setActiveAccount(response.account);
                updateUI(response.account);
            } else {
                const account = pca.getAllAccounts()[0];
                updateUI(account);
            }
        }).catch((error) => {
            console.log(error);
        });

        // attach event handlers to button clicks
        loginButton.addEventListener('click', () => {
            pca.loginPopup().then((response) => {
                pca.setActiveAccount(response.account);
                updateUI(response.account);
            })
        });

        logoutButton.addEventListener('click', () => {
            pca.logoutPopup().then((response) => {
                window.location.reload();
            });
        });

        tokenButton.addEventListener('click', () => {
            const account = pca.getActiveAccount();

            pca.acquireTokenSilent({
                account: account,
                scopes: ["User.Read"]
            }).then((response) => {
                console.log(response);
            }).catch((error) => {
                if (error instanceof msal.InteractionRequiredAuthError) {
                    pca.acquireTokenPopup({
                        scopes: ["User.Read"]
                    }).then((response) => {
                        console.log(response);
                    });
                }

                console.log(error);
            });
        });
    </script>
</body>

</html>

További lépések