Jak migrovat Node.js aplikaci z knihovny ADAL do KNIHOVNY MSAL

Microsoft Authentication Library for Node (MSAL Node ) je teď doporučenou sadou SDK pro povolení ověřování a autorizace pro vaše aplikace zaregistrované na platformě Microsoft Identity Platform. Tento článek popisuje důležité kroky, které je potřeba provést, abyste mohli migrovat aplikace z knihovny Active Directory Authentication Library for Node (uzel ADAL) do uzlu MSAL.

Požadavky

  • Uzel verze 10, 12, 14, 16 nebo 18. Prohlédněte si poznámku k podpoře verzí.

Aktualizace nastavení registrace aplikace

Při práci s uzlem ADAL jste pravděpodobně používali koncový bod Azure AD verze 1.0. Aplikace migrující z ADAL na MSAL by se měly přepnout na koncový bod Azure AD v2.0.

Instalace a import knihovny MSAL

  1. nainstalujte balíček uzlu MSAL prostřednictvím npm:
  npm install @azure/msal-node
  1. Potom naimportujte uzel MSAL do kódu:
  const msal = require('@azure/msal-node');
  1. Nakonec odinstalujte balíček ADAL Node a odeberte všechny odkazy v kódu:
  npm uninstall adal-node

Inicializace knihovny MSAL

V uzlu ADAL inicializujete AuthenticationContext objekt, který pak zveřejňuje metody, které můžete použít v různých tocích ověřování (například acquireTokenWithAuthorizationCode pro webové aplikace). Při inicializaci je jediným povinným parametrem identifikátor URI autority:

var adal = require('adal-node');

var authorityURI = "https://login.microsoftonline.com/common";
var authenticationContex = new adal.AuthenticationContext(authorityURI);

V uzlu MSAL máte dvě alternativy: Pokud vytváříte mobilní aplikaci nebo desktopovou aplikaci, vytvoříte instanci objektu PublicClientApplication . Konstruktor očekává objekt konfigurace , který obsahuje clientId alespoň parametr. Pokud ho nezadáte, nastaví msAL identifikátor URI https://login.microsoftonline.com/common autority.

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

const pca = new msal.PublicClientApplication({
        auth: {
            clientId: "YOUR_CLIENT_ID"
        }
    });

Poznámka:

Pokud autoritu https://login.microsoftonline.com/common používáte ve verzi 2.0, umožníte uživatelům přihlásit se pomocí jakékoli organizace Microsoft Entra nebo osobního účtu Microsoft (MSA). Pokud chcete v uzlu MSAL omezit přihlášení k libovolnému účtu Microsoft Entra (stejné chování jako u uzlu ADAL), použijte https://login.microsoftonline.com/organizations místo toho.

Na druhou stranu, pokud vytváříte webovou aplikaci nebo aplikaci démona, vytvoříte instanci objektu ConfidentialClientApplication . U takových aplikací musíte také zadat přihlašovací údaje klienta, jako je tajný klíč klienta nebo certifikát:

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

const cca = new msal.ConfidentialClientApplication({
        auth: {
            clientId: "YOUR_CLIENT_ID",
            clientSecret: "YOUR_CLIENT_SECRET"
        }
    });

ConfidentialClientApplicationNa PublicClientApplication rozdíl od knihovny ADAL AuthenticationContextje vázáno na ID klienta. To znamená, že pokud máte různá ID klienta, která chcete použít ve své aplikaci, musíte vytvořit instanci nové instance MSAL pro každou z nich. Další informace: Inicializace uzlu MSAL

Konfigurace KNIHOVNY MSAL

Při vytváření aplikací na platformě Microsoft Identity Platform bude vaše aplikace obsahovat mnoho parametrů souvisejících s ověřováním. V uzlu AuthenticationContext ADAL má objekt omezený počet parametrů konfigurace, se kterými můžete vytvořit instanci, zatímco zbývající parametry ve vašem kódu volně zavěsí (například clientSecret):

var adal = require('adal-node');

var authority = "https://login.microsoftonline.com/YOUR_TENANT_ID"
var validateAuthority = true,
var cache = null;

var authenticationContext = new adal.AuthenticationContext(authority, validateAuthority, cache);
  • authority: Adresa URL identifikující autoritu tokenu
  • validateAuthority: funkce, která brání kódu v vyžádání tokenů od potenciálně škodlivé autority.
  • cache: Nastaví mezipaměť tokenů používanou touto instancí AuthenticationContext. Pokud tento parametr není nastavený, použije se výchozí hodnota v mezipaměti paměti.

Uzel MSAL na druhé straně používá objekt konfigurace typu Konfigurace. Obsahuje následující vlastnosti:

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

const msalConfig = {
    auth: {
        clientId: "YOUR_CLIENT_ID",
        authority: "https://login.microsoftonline.com/YOUR_TENANT_ID",
        clientSecret: "YOUR_CLIENT_SECRET",
        knownAuthorities: [],
    },
    cache: {
        // your implementation of caching
    },
    system: {
        loggerOptions: { /** logging related options */ }
    }
}


const cca = new msal.ConfidentialClientApplication(msalConfig);

Jako klíčový rozdíl msAL nemá příznak k zakázání ověření autority a autority jsou ve výchozím nastavení vždy ověřeny. Knihovna MSAL porovnává požadovanou autoritu se seznamem autorit známých microsoftem nebo seznamem autorit, které jste zadali ve své konfiguraci. Další informace: Možnosti konfigurace

Přepnutí na rozhraní MSAL API

Většina veřejných metod v uzlu ADAL má ekvivalenty v uzlu MSAL:

ADAL MSAL Notes
acquireToken acquireTokenSilent Přejmenováno a nyní očekává objekt účtu
acquireTokenWithAuthorizationCode acquireTokenByCode
acquireTokenWithClientCredentials acquireTokenByClientCredential
acquireTokenWithRefreshToken acquireTokenByRefreshToken Užitečné pro migraci platných obnovovacích tokenů
acquireTokenWithDeviceCode acquireTokenByDeviceCode Nyní abstrahuje získání uživatelského kódu (viz níže).
acquireTokenWithUsernamePassword acquireTokenByUsernamePassword

Některé metody v uzlu ADAL jsou však zastaralé, zatímco uzel MSAL nabízí nové metody:

ADAL MSAL Notes
acquireUserCode Sloučeno s acquireTokeByDeviceCode (viz výše)
acquireTokenOnBehalfOf Nová metoda, která abstrahuje tok OBO
acquireTokenWithClientCertificate Už není potřeba, protože certifikáty se při inicializaci přiřazují (viz možnosti konfigurace).
getAuthCodeUrl Nová metoda, která abstrahuje vytváření adres URL koncového bodu

Použití oborů místo prostředků

Důležitým rozdílem mezi koncovými body v1.0 a v2.0 je způsob přístupu k prostředkům. V uzlu ADAL byste nejprve zaregistrovali oprávnění na portálu pro registraci aplikací a pak požádali o přístupový token pro prostředek (například Microsoft Graph), jak je znázorněno níže:

authenticationContext.acquireTokenWithAuthorizationCode(
    req.query.code,
    redirectUri,
    resource, // e.g. 'https://graph.microsoft.com'
    clientId,
    clientSecret,
    function (err, response) {
        // do something with the authentication response
    }
);

Uzel MSAL podporuje pouze koncový bod verze 2.0 . Koncový bod v2.0 využívá model orientovaný na rozsah pro přístup k prostředkům. Proto při vyžádání přístupového tokenu pro prostředek musíte také zadat rozsah pro tento prostředek:

const tokenRequest = {
    code: req.query.code,
    scopes: ["https://graph.microsoft.com/User.Read"],
    redirectUri: REDIRECT_URI,
};

pca.acquireTokenByCode(tokenRequest).then((response) => {
    // do something with the authentication response
}).catch((error) => {
    console.log(error);
});

Jednou z výhod modelu zaměřeného na obor je schopnost používat dynamické obory. Při vytváření aplikací pomocí verze 1.0 jste museli zaregistrovat úplnou sadu oprávnění (označovanou jako statické obory), kterou aplikace vyžaduje, aby uživatel souhlasil při přihlášení. V 2.0 můžete použít parametr oboru k vyžádání oprávnění v době, kdy je chcete (tedy dynamické obory). To uživateli umožňuje poskytnout přírůstkový souhlas s obory. Takže pokud na začátku chcete, aby se uživatel přihlásil k vaší aplikaci a nepotřebujete žádný druh přístupu, můžete to udělat. Pokud později potřebujete možnost číst kalendář uživatele, můžete požádat o rozsah kalendáře v metodách acquireToken a získat souhlas uživatele. Další informace: Prostředky a obory

Použití příslibů místo zpětných volání

V uzlu ADAL se zpětná volání po úspěšném ověření použijí pro jakoukoli operaci a získá se odpověď:

var context = new AuthenticationContext(authorityUrl, validateAuthority);

context.acquireTokenWithClientCredentials(resource, clientId, clientSecret, function(err, response) {
    if (err) {
        console.log(err);
    } else {
        // do something with the authentication response
    }
});

V uzlu MSAL se místo toho používají přísliby:

    const cca = new msal.ConfidentialClientApplication(msalConfig);

    cca.acquireTokenByClientCredential(tokenRequest).then((response) => {
        // do something with the authentication response
    }).catch((error) => {
        console.log(error);
    });

Můžete také použít syntaxi async/await , která je součástí ES8:

    try {
        const authResponse = await cca.acquireTokenByCode(tokenRequest);
    } catch (error) {
        console.log(error);
    }

Povolit protokolování

V uzlu ADAL nakonfigurujete protokolování samostatně na libovolném místě v kódu:

var adal = require('adal-node');

//PII or OII logging disabled. Default Logger does not capture any PII or OII.
adal.logging.setLoggingOptions({
  log: function (level, message, error) {
    console.log(message);

    if (error) {
        console.log(error);
    }
  },
  level: logging.LOGGING_LEVEL.VERBOSE, // provide the logging level
  loggingWithPII: false  // Determine if you want to log personal identification information. The default value is false.
});

V uzlu MSAL je protokolování součástí možností konfigurace a vytvoří se s inicializací instance uzlu MSAL:

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

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 cca = new msal.ConfidentialClientApplication(msalConfig);

Povolení ukládání tokenů do mezipaměti

V uzlu ADAL jste měli možnost importovat mezipaměť tokenů v paměti. Mezipaměť tokenů se používá jako parametr při inicializaci objektu AuthenticationContext :

var MemoryCache = require('adal-node/lib/memory-cache');

var cache = new MemoryCache();
var authorityURI = "https://login.microsoftonline.com/common";

var context = new AuthenticationContext(authorityURI, true, cache);

Uzel MSAL ve výchozím nastavení používá mezipaměť tokenů v paměti. Nemusíte ho explicitně importovat; Mezipaměť tokenů v paměti je zpřístupněna jako součást ConfidentialClientApplication a PublicClientApplication třídy.

const msalTokenCache = publicClientApplication.getTokenCache();

Důležité je, že předchozí mezipaměť tokenů s uzlem ADAL se nedá přenést do uzlu MSAL, protože schémata mezipaměti nejsou kompatibilní. Můžete ale použít platné obnovovací tokeny, které vaše aplikace získala dříve s uzlem ADAL v uzlu MSAL. Další informace najdete v části o obnovovacích tokenech .

Mezipaměť můžete také zapsat na disk poskytnutím vlastního modulu plug-in mezipaměti. Modul plug-in mezipaměti musí implementovat rozhraní ICachePlugin. Podobně jako protokolování je ukládání do mezipaměti součástí možností konfigurace a vytvoří se s inicializací instance uzlu MSAL:

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

const msalConfig = {
    auth: {
        // authentication related parameters
    },
    cache: {
        cachePlugin // your implementation of cache plugin
    },
    system: {
        // logging related options
    }
}

const msalInstance = new ConfidentialClientApplication(msalConfig);

Příklad modulu plug-in mezipaměti je možné implementovat takto:

const fs = require('fs');

// Call back APIs which automatically write and read into a .json file - example implementation
const beforeCacheAccess = async (cacheContext) => {
    cacheContext.tokenCache.deserialize(await fs.readFile(cachePath, "utf-8"));
};

const afterCacheAccess = async (cacheContext) => {
    if(cacheContext.cacheHasChanged) {
        await fs.writeFile(cachePath, cacheContext.tokenCache.serialize());
    }
};

// Cache Plugin
const cachePlugin = {
    beforeCacheAccess,
    afterCacheAccess
};

Pokud vyvíjíte veřejné klientské aplikace, jako jsou desktopové aplikace , nabízí rozšíření Microsoft Authentication Extensions for Node zabezpečené mechanismy pro klientské aplikace, které umožňují serializaci a trvalost mezi platformami mezipaměti tokenů. Podporované platformy jsou Windows, Mac a Linux.

Poznámka:

Rozšíření ověřování Microsoftu pro Node se pro webové aplikace nedoporučuje , protože může vést k problémům s škálováním a výkonem. Místo toho se doporučuje, aby webové aplikace uchovávaly mezipaměť v relaci.

Odebrání logiky kolem obnovovacích tokenů

V uzlu ADAL byly vystaveny obnovovací tokeny (RT), které umožňují vyvíjet řešení týkající se použití těchto tokenů tím, že je uložíte do mezipaměti a použijete metodu acquireTokenWithRefreshToken . Typické scénáře, ve kterých jsou zvlášť relevantní RT:

  • Dlouhotrvající služby, které provádějí akce, včetně aktualizace řídicích panelů jménem uživatelů, kteří už nejsou připojení.
  • Scénáře WebFarm umožňující klientovi přenést rt do webové služby (ukládání do mezipaměti se provádí na straně klienta, šifrovaný soubor cookie a ne na straně serveru).

Uzel MSAL spolu s jinými seznamy MSALs nezpřístupňuje obnovovací tokeny z bezpečnostních důvodů. Místo toho msAL zpracovává obnovovací tokeny za vás. Proto už pro to nemusíte vytvářet logiku. Pomocí dříve získaných (a stále platných) obnovovacích tokenů z mezipaměti uzlu ADAL ale můžete získat novou sadu tokenů s uzlem MSAL. K tomu msAL Node nabízí acquireTokenByRefreshToken, což je ekvivalent metody ADAL Node acquireTokenWithRefreshToken :

var msal = require('@azure/msal-node');

const config = {
    auth: {
        clientId: "ENTER_CLIENT_ID",
        authority: "https://login.microsoftonline.com/ENTER_TENANT_ID",
        clientSecret: "ENTER_CLIENT_SECRET"
    }
};

const cca = new msal.ConfidentialClientApplication(config);

const refreshTokenRequest = {
    refreshToken: "", // your previous refresh token here
    scopes: ["https://graph.microsoft.com/.default"],
    forceCache: true,
};

cca.acquireTokenByRefreshToken(refreshTokenRequest).then((response) => {
    console.log(response);
}).catch((error) => {
    console.log(error);
});

Další informace najdete v ukázce migrace uzlu ADAL na uzel MSAL.

Poznámka:

Doporučujeme zničit starší mezipaměť tokenů uzlu ADAL, jakmile využijete stále platné obnovovací tokeny k získání nové sady tokenů pomocí metody uzlu acquireTokenByRefreshToken MSAL, jak je znázorněno výše.

Zpracování chyb a výjimek

Při použití uzlu MSAL je interaction_required nejběžnějším typem chyby, se kterou se můžete setkat. Tato chyba se často řeší zahájením interaktivní výzvy k získání tokenu. Pokud například nepoužíváte acquireTokenSilenttokeny aktualizace uložené v mezipaměti, uzel MSAL nebude moct získat přístupový token bezobslužně. Podobně webové rozhraní API, ke kterým se pokoušíte získat přístup, může mít zavedené zásady podmíněného přístupu, které vyžadují, aby uživatel provedl vícefaktorové ověřování (MFA). V takových případech se při zpracování interaction_required chyby aktivací acquireTokenByCode uživateli zobrazí výzva k vícefaktorovém ověřování, což mu umožní ho zaplnit.

Další běžnou chybou, se kterou se můžete setkat, je consent_required, k níž dochází v případě, že uživatel nesouhlasí s oprávněními potřebnými k získání přístupového tokenu pro chráněný prostředek. Stejně jako v interaction_requiredpřípadě, řešení consent_required chyby často iniciuje interaktivní výzvu k získání tokenu acquireTokenByCode pomocí metody.

Spustit aplikaci

Po dokončení změn spusťte aplikaci a otestujte scénář ověřování:

npm start

Příklad: Získání tokenů pomocí uzlu ADAL vs. uzlu MSAL

Následující fragment kódu ukazuje důvěrnou webovou aplikaci klienta v Express.js frameworku. Provede přihlášení, když uživatel přejde na trasu /authověřování , získá přístupový token pro Microsoft Graph přes /redirect trasu a pak zobrazí obsah uvedeného tokenu.

Použití uzlu ADAL Použití uzlu MSAL
// Import dependencies
var express = require('express');
var crypto = require('crypto');
var adal = require('adal-node');

// Authentication parameters
var clientId = 'Enter_the_Application_Id_Here';
var clientSecret = 'Enter_the_Client_Secret_Here';
var tenant = 'Enter_the_Tenant_Info_Here';
var authorityUrl = 'https://login.microsoftonline.com/' + tenant;
var redirectUri = 'http://localhost:3000/redirect';
var resource = 'https://graph.microsoft.com';

// Configure logging
adal.Logging.setLoggingOptions({
    log: function (level, message, error) {
        console.log(message);
    },
    level: adal.Logging.LOGGING_LEVEL.VERBOSE,
    loggingWithPII: false
});

// Auth code request URL template
var templateAuthzUrl = 'https://login.microsoftonline.com/'
    + tenant + '/oauth2/authorize?response_type=code&client_id='
    + clientId + '&redirect_uri=' + redirectUri
    + '&state=<state>&resource=' + resource;

// Initialize express
var app = express();

// State variable persists throughout the app lifetime
app.locals.state = "";

app.get('/auth', function(req, res) {

    // Create a random string to use against XSRF
    crypto.randomBytes(48, function(ex, buf) {
        app.locals.state = buf.toString('base64')
            .replace(/\//g, '_')
            .replace(/\+/g, '-');

        // Construct auth code request URL
        var authorizationUrl = templateAuthzUrl
            .replace('<state>', app.locals.state);

        res.redirect(authorizationUrl);
    });
});

app.get('/redirect', function(req, res) {
    // Compare state parameter against XSRF
    if (app.locals.state !== req.query.state) {
        res.send('error: state does not match');
    }

    // Initialize an AuthenticationContext object
    var authenticationContext =
        new adal.AuthenticationContext(authorityUrl);

    // Exchange auth code for tokens
    authenticationContext.acquireTokenWithAuthorizationCode(
        req.query.code,
        redirectUri,
        resource,
        clientId,
        clientSecret,
        function(err, response) {
            res.send(response);
        }
    );
});

app.listen(3000, function() {
    console.log(`listening on port 3000!`);
});
// Import dependencies
const express = require("express");
const msal = require('@azure/msal-node');

// Authentication parameters
const config = {
    auth: {
        clientId: "Enter_the_Application_Id_Here",
        authority: "https://login.microsoftonline.com/Enter_the_Tenant_Info_Here",
        clientSecret: "Enter_the_Client_Secret_Here"
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
};

const REDIRECT_URI = "http://localhost:3000/redirect";

// Initialize MSAL Node object using authentication parameters
const cca = new msal.ConfidentialClientApplication(config);

// Initialize express
const app = express();

app.get('/auth', (req, res) => {

    // Construct a request object for auth code
    const authCodeUrlParameters = {
        scopes: ["user.read"],
        redirectUri: REDIRECT_URI,
    };

    // Request auth code, then redirect
    cca.getAuthCodeUrl(authCodeUrlParameters)
        .then((response) => {
            res.redirect(response);
        }).catch((error) => res.send(error));
});

app.get('/redirect', (req, res) => {

    // Use the auth code in redirect request to construct
    // a token request object
    const tokenRequest = {
        code: req.query.code,
        scopes: ["user.read"],
        redirectUri: REDIRECT_URI,
    };

    // Exchange the auth code for tokens
    cca.acquireTokenByCode(tokenRequest)
        .then((response) => {
            res.send(response);
        }).catch((error) => res.status(500).send(error));
});

app.listen(3000, () =>
    console.log(`listening on port 3000!`));

Další kroky