Freigeben über


Migrieren einer Node.js-Anwendung von ADAL zu MSAL

Microsoft Authentication Library for Node (MSAL Node) ist jetzt das empfohlene SDK zum Aktivieren der Authentifizierung und Autorisierung für Ihre Anwendungen, die auf der Microsoft Identity Platform registriert sind. In diesem Artikel werden die wichtigen Schritte behandelt, die Sie ausführen müssen, um Ihre Apps von Active Directory Authentifizierungsbibliothek für Knoten (ADAL Node) zu MSAL Node zu migrieren.

Voraussetzungen

Aktualisieren der App-Registrierungseinstellungen

Beim Arbeiten mit ADAL Node haben Sie wahrscheinlich den Azure AD v1.0-Endpunkt verwendet. Apps, die von ADAL zu MSAL migrieren, sollten zu Azure AD v2.0-Endpunkt wechseln.

Installieren und Importieren von MSAL

  1. Installieren Sie das MSAL Node-Paket über npm:
  npm install @azure/msal-node
  1. Importieren Sie MSAL Node danach in den Code:
  const msal = require('@azure/msal-node');
  1. Deinstallieren Sie schließlich das ADAL Node-Paket, und entfernen Sie alle Verweise im Code:
  npm uninstall adal-node

MSAL initialisieren

In ADAL Node initialisieren Sie ein AuthenticationContext Objekt, das dann die Methoden verfügbar macht, die Sie in verschiedenen Authentifizierungsflüssen verwenden können (z acquireTokenWithAuthorizationCode . B. für Web-Apps). Beim Initialisieren ist der einzige obligatorische Parameter der Autoritäts-URI:

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

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

In MSAL Node haben Sie stattdessen zwei Alternativen: Wenn Sie eine mobile App oder eine Desktop-App erstellen, instanziieren Sie ein PublicClientApplication Objekt. Der Konstruktor erwartet mindestens ein Konfigurationsobjekt , das den clientId Parameter enthält. MSAL setzt den Autoritäts-URI standardmäßig auf https://login.microsoftonline.com/common, wenn Sie ihn nicht angeben.

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

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

Hinweis

Wenn Sie die https://login.microsoftonline.com/common Authority in v2.0 verwenden, können sich Benutzer mit jeder Microsoft Entra Organisation oder einem persönlichen Microsoft-Konto (MSA) anmelden. Wenn Sie in MSAL Node die Anmeldung auf ein beliebiges Microsoft Entra Konto beschränken möchten (dasselbe Verhalten wie bei ADAL Node), verwenden Sie stattdessen https://login.microsoftonline.com/organizations.

Wenn Sie hingegen eine Web-App oder eine Daemon-App erstellen, instanziieren Sie ein ConfidentialClientApplication Objekt. Bei solchen Apps müssen Sie auch eine Clientanmeldeinformationen angeben, z. B. einen geheimen Clientschlüssel oder ein Zertifikat:

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

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

Sowohl PublicClientApplication als auch ConfidentialClientApplication sind im Gegensatz zu ADALs AuthenticationContext an eine Client-ID gebunden. Das bedeutet, dass Sie bei unterschiedlichen Client-IDs, die in Ihrer Anwendung verwendet werden sollen, für jede ID eine neue MSAL-Instanz instanziieren müssen. Weitere Informationen finden Sie unter Initialisierung von MSAL Node

Konfigurieren von MSAL

Beim Erstellen von Apps in Microsoft Identity Platform enthalten die Apps zahlreiche Parameter, die mit der Authentifizierung zusammenhängen. In ADAL Node verfügt das AuthenticationContext Objekt über eine begrenzte Anzahl von Konfigurationsparametern, mit denen Sie sie instanziieren können, während die verbleibenden Parameter im Code frei hängen (z. B. 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: URL, die eine Tokenautorität identifiziert
  • validateAuthority: ein Feature, das verhindert, dass Ihr Code Token von einer potenziell schädlichen Autorität anfordert
  • cache: legt den tokencache fest, der von dieser AuthenticationContext-Instanz verwendet wird. Wenn dieser Parameter nicht festgelegt ist, wird standardmäßig der In-Memory-Cache verwendet.

MSAL Node verwendet dagegen ein Konfigurationsobjekt vom Typ "Configuration". Es enthält die folgenden Eigenschaften:

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

Ein wesentlicher Unterschied besteht darin, dass MSAL kein Flag zum Deaktivieren der Autoritätsüberprüfung bietet und die Autoritäten standardmäßig immer überprüft werden. In MSAL wird die angeforderte Autorität mit einer Liste von in Microsoft bekannten Autoritäten oder einer Liste von Autoritäten verglichen, die Sie in der Konfiguration angegeben haben. Weitere Informationen finden Sie unter: Konfigurationsoptionen

Wechseln zur MSAL-API

Die meisten öffentlichen Methoden in ADAL Node verfügen über Entsprechungen in MSAL Node:

ADAL MSAL Hinweise
acquireToken acquireTokenSilent Umbenannt und erwartet jetzt ein Kontoobjekt
acquireTokenWithAuthorizationCode acquireTokenByCode
acquireTokenWithClientCredentials acquireTokenByClientCredential
acquireTokenWithRefreshToken acquireTokenByRefreshToken Hilfreich für die Migration gültiger Refresh-Token
acquireTokenWithDeviceCode acquireTokenByDeviceCode Abstrahiert nun die Erfassung des Benutzercodes (siehe unten)
acquireTokenWithUsernamePassword acquireTokenByUsernamePassword

Einige Methoden in ADAL Node sind jedoch veraltet. MSAL Node bietet hingegen neue Methoden:

ADAL MSAL Hinweise
acquireUserCode n/v Zusammengeführt mit acquireTokeByDeviceCode (siehe oben)
n/v acquireTokenOnBehalfOf Eine neue Methode, die den OBO-Fluss abstrahiert
acquireTokenWithClientCertificate n/v Nicht mehr erforderlich, da Zertifikate jetzt während der Initialisierung zugewiesen werden (siehe Konfigurationsoptionen)
n/v getAuthCodeUrl Ein neues Verfahren, das den Aufbau der Authorize Endpoint-URL abstrahiert

Verwenden Sie Bereiche anstelle von Ressourcen

Ein wichtiger Unterschied zwischen v1.0- und v2.0-Endpunkten besteht im Zugriff auf die Ressourcen. In ADAL Node würden Sie zuerst eine Berechtigung im App-Registrierungsportal registrieren und dann ein Zugriffstoken für eine Ressource (z. B. Microsoft Graph) anfordern, wie unten gezeigt:

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

MSAL Node unterstützt nur den v2.0-Endpunkt . Der v2.0-Endpunkt verwendet ein bereichsorientiertes Modell für den Zugriff auf Ressourcen. Wenn Sie also ein Zugriffstoken für eine Ressource anfordern, müssen Sie auch den Bereich für die Ressource angeben:

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

Ein Vorteil des bereichsorientierten Modells ist die Möglichkeit, dynamische Bereiche zu verwenden. Beim Erstellen von Anwendungen mit v1.0 mussten Sie den vollständigen Satz von Berechtigungen, die von der Anwendung für den Benutzer zum Zeitpunkt des Anmeldevorgangs erforderlich sind und als statische Bereiche bezeichnet werden, registrieren. In v2.0 können Sie den Bereichsparameter verwenden, um die Berechtigungen zum gewünschten Zeitpunkt anzufordern (daher dynamische Bereiche). Auf diese Weise kann der Benutzer inkrementelle Zustimmung zu Bereichen bereitstellen. Wenn Sie also am Anfang nur möchten, dass sich der Benutzer bei Ihrer Anwendung anmeldet und Sie keinen Zugriff benötigen, können Sie dies tun. Wenn Sie später in der Lage sein müssen, den Kalender der benutzenden Person zu lesen, können Sie dann den Kalendergeltungsbereich in den acquireToken-Methoden anfordern und die Einwilligung der benutzenden Person einholen. Weitere Informationen finden Sie unter: Ressourcen und Bereiche

Verwenden von Zusagen anstelle von Rückrufen

In ADAL Node werden Rückrufe für jeden Vorgang verwendet, nachdem die Authentifizierung erfolgreich war, und es wird eine Antwort abgerufen:

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

In MSAL Node werden stattdessen Zusagen verwendet:

    const cca = new msal.ConfidentialClientApplication(msalConfig);

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

Sie können auch die async/await-Syntax verwenden, die im Lieferumfang von ES8 steht:

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

Aktivieren der Protokollierung

In ADAL Node konfigurieren Sie die Protokollierung separat an einer beliebigen Stelle im Code:

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

In MSAL Node ist die Protokollierung Teil der Konfigurationsoptionen und wird bei der Initialisierung der MSAL Node-Instanz erstellt:

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

Token-Zwischenspeicherung aktivieren

In ADAL Node bestand die Möglichkeit, einen In-Memory-Tokencache zu importieren. Der Tokencache wird beim Initialisieren eines AuthenticationContext Objekts als Parameter verwendet:

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

In MSAL Node ist der In-Memory-Tokencache die Standardeinstellung. Sie müssen diesen nicht explizit importieren; der In-Memory-Tokencache wird als Teil der ConfidentialClientApplication- und PublicClientApplication-Klassen verfügbar gemacht.

const msalTokenCache = publicClientApplication.getTokenCache();

Wichtig: Ihr vorheriger Tokencache mit ADAL Node kann nicht auf MSAL Node übertragen werden, da Cacheschemas nicht kompatibel sind. Sie können jedoch in MSAL Node die gültigen Aktualisierungstoken verwenden, die Ihre App zuvor mit ADAL Node abgerufen hat. Weitere Informationen finden Sie im Abschnitt zu Aktualisierungstoken .

Sie können ihren Cache auch auf den Datenträger schreiben, indem Sie Ihr eigenes Cache-Plug-In bereitstellen. Das Cache-Plug-In muss die Schnittstelle ICachePluginimplementieren. Wie die Protokollierung ist die Zwischenspeicherung Teil der Konfigurationsoptionen und wird bei der Initialisierung der MSAL Node-Instanz erstellt:

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

Ein Cache-Plug-In kann wie im folgenden Beispiel implementiert werden:

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

Wenn Sie öffentliche Clientanwendungen wie Desktop-Apps entwickeln, bietet die Microsoft-Authentifizierungserweiterung für Node sichere Mechanismen für Clientanwendungen, um plattformübergreifende Tokencache-Serialisierung und Persistenz durchzuführen. Unterstützte Plattformen sind Windows, Mac und Linux.

Hinweis

Microsoft-Authentifizierungserweiterungen für Node werden für Webanwendungennicht empfohlen, da sie zu Skalierungs- und Leistungsproblemen führen können. Stattdessen wird bei Web-Apps empfohlen, den Cache in der Sitzung zu speichern.

Entfernen von Logik für Aktualisierungstoken

In ADAL Node wurden die Aktualisierungstoken (RT) verfügbar gemacht, sodass Sie Lösungen für die Verwendung dieser Token entwickeln können, indem Sie sie zwischenspeichern und die acquireTokenWithRefreshToken Methode verwenden. Typische Szenarien, in denen Aktualisierungstoken besonders relevant sind:

  • Zeitintensive Dienste, über die verschiedene Aktionen (beispielsweise Aktualisieren von Dashboards) für Benutzer ausgeführt werden, wenn die Benutzer nicht mehr verbunden sind.
  • WebFarm-Szenarien, die es dem Client ermöglichen, das Aktualisierungstoken im Webdienst zur Verfügung zu stellen (Die Zwischenspeicherung erfolgt auf Client- und nicht auf Serverseite in einem verschlüsselten Cookie.)

MSAL Node sowie andere MSALs geben Aktualisierungstoken aus Sicherheitsgründen nicht heraus. Stattdessen übernimmt MSAL das Aktualisieren von Token für Sie. Daher muss dafür keine Logik mehr erstellt werden. Sie können jedoch Ihre zuvor erworbenen (und weiterhin gültigen) Aktualisierungstoken aus dem Cache von ADAL Node verwenden, um einen neuen Satz von Token mit MSAL Node abzurufen. MSAL Node bietet dazu acquireTokenByRefreshToken an, das der Methode von acquireTokenWithRefreshToken ADAL Node entspricht.

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

Weitere Informationen finden Sie in den MSAL Node-Beispielen.

Hinweis

Es wird empfohlen, den älteren ADAL-Knotentokencache zu zerstören, sobald Sie die noch gültigen Aktualisierungstoken verwenden, um einen neuen Satz von Token mithilfe der Methode des MSAL-Knotens acquireTokenByRefreshToken abzurufen, wie oben gezeigt.

Behandeln von Fehlern und Ausnahmen

Bei Verwendung von MSAL Node ist der häufigste Fehlertyp, den Sie möglicherweise haben, der interaction_required Fehler. Dieser Fehler kann häufig durch Initiierung einer interaktiven Tokenerfassungsaufforderung behoben werden. Wenn beispielsweise keine zwischengespeicherten Aktualisierungstoken bei der Verwendung von acquireTokenSilent vorhanden sind, kann MSAL Node kein Zugriffstoken im Hintergrund abrufen. Ebenso verfügt die Web-API, auf die Sie zugreifen möchten, möglicherweise über eine Richtlinie für bedingten Zugriff , die den Benutzer für die mehrstufige Authentifizierung (Multi-Factor Authentication, MFA) benötigt. In solchen Fällen wird ein Fehler durch Auslösen von acquireTokenByCode behandelt, wodurch dem Benutzer die Multi-Faktor-Authentifizierung (MFA) ermöglicht wird, damit er sie erfüllen kann.

Ein weiterer häufiger Fehler, den Sie möglicherweise sehen können, ist consent_required, was auftritt, wenn Berechtigungen, die zum Abrufen eines Zugriffstokens für eine geschützte Ressource erforderlich sind, vom Benutzer nicht zugestimmt werden. Wie bei interaction_required, der Lösung für den Fehler consent_required, wird häufig eine Aufforderung zur interaktiven Tokenakquisition durch die acquireTokenByCode-Methode initiiert.

Ausführen der App

Nachdem Sie die gewünschten Änderungen vorgenommen haben, können Sie die App ausführen und das Authentifizierungsszenario testen:

npm start

Beispiel: Abrufen von Token mit ADAL Node und MSAL Node

Der folgende Codeausschnitt veranschaulicht eine vertrauliche Client-Web-App im Express.js-Framework. Sie führt eine Anmeldung durch, wenn ein Benutzer auf die Authentifizierungsroute /auth trifft, ein Zugriffstoken für Microsoft Graph über die Route /redirect abruft und dann den Inhalt des genannten Tokens anzeigt.

Verwenden von ADAL Node Verwenden von MSAL Node
// 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!`));

Nächste Schritte