Zwischenspeichern von Token im MSAL-Knoten

Wenn MSAL Node ein Token abruft, wird es zur späteren Verwendung im Arbeitsspeicher zwischengespeichert. MSAL Node verwaltet die Tokenlebensdauer und die Aktualisierung für Sie. APIs wie acquireTokenSilent() ruft Zugriffstoken aus dem Cache für ein bestimmtes Konto ab:

MSAL macht Aktualisierungstoken aus Sicherheitsgründen nicht verfügbar. Weitere Informationen zum Abrufen der Aktualisierungstoken finden Sie in den häufig gestellten Fragen .

Sicheres Verwenden von geheimen Clientschlüsseln

Geheime Clientschlüssel sollten niemals hartcodiert werden. Das dotenv npm-Paket kann verwendet werden, um geheime Schlüssel in einer env-Datei (im Stammverzeichnis des Projekts) zu speichern, die in gitignore enthalten sein sollte, um versehentliche Uploads der geheimen Schlüssel zu verhindern.

const msal = require('@azure/msal-node');
require('dotenv').config(); // process.env now has the values defined in a .env file

// Create msal application object
const cca = new msal.ConfidentialClientApplication({
    auth: {
        clientId: "Enter_the_Application_Id_Here", // e.g. "00001111-aaaa-2222-bbbb-3333cccc4444" (guid)
        authority: "https://login.microsoftonline.com/Enter_the_Tenant_Info_Here", // e.g. "common" or your tenantId (guid)
        clientSecret: process.env.clientSecret // obtained during app registration
    }
});

/**
* acquireToken* APIs return an account object containing the "homeAccountId"
* you should keep a record of this in your app and use it later on when calling acquireTokenSilent
*/
const someUserHomeAccountId = "Enter_User_Home_Account_Id";

const msalTokenCache = cca.getTokenCache();
const account = await msalTokenCache.getAccountByHomeId(someUserHomeAccountId);

const silentTokenRequest = {
    account: account,
    scopes: ["User.Read"],
};

cca.acquireTokenSilent(silentTokenRequest).then((response) => {
    // do something with response
}).catch((error) => {
    // catch and handle errors
});

In der Produktion möchten Sie wahrscheinlich den Tokencache serialisieren und beibehalten. Je nach Anwendungstyp können Sie:

  • Desktop-Apps, Konsolen-Apps (Öffentliche Clients-Apps (PCA)):
    • Verwenden Sie MSAL Node Extensions, das Persistenz- und Verschlüsselungslösungen für ruhende Daten unter Windows, Linux und Mac OS bereitstellt.
  • Web-Apps, Web-APIs, Daemon-Apps (vertrauliche Client-Apps (CCA)):
    • Der In-Memory-Tokencache von MSAL ist für den Produktionseinsatz nicht skalierbar. Verwenden Sie das Muster für verteilte Tokenzwischenspeicherung, um den Cache in einer Speicherumgebung Ihrer Wahl zu persistieren (Redis, MongoDB, SQL-Datenbanken usw. – beachten Sie, dass Sie diese auch gemeinsam verwenden können, z. B. einen Redis-ähnlichen In-Memory-Cache als erste Persistenzschicht und eine SQL-Datenbank als zweite, stabilere Persistenzschicht).

In-Memory-Cache

MSAL verwaltet einen Speichercache. Der Speichercache ist repräsentativ für den Anwendungscachestatus. Die Lebensdauer des In-Memory-Caches entspricht dem MSAL-Anwendungsobjekt. Wenn der Prozess mit MSAL neu gestartet wird, wird der Cache gelöscht, wenn der Prozesslebenszyklus abgeschlossen ist. Wenn der In-Memory-Cache leer ist und kein persistenter Cache zum Wiederherstellen des Caches vorhanden ist, müssen benutzer sich erneut authentifizieren. Wenn der Benutzer in diesem Fall noch über eine aktive Sitzung mit Microsoft Entra ID verfügt, kann er sich ohne Aufforderungen erneut authentifizieren, dies beeinträchtigt jedoch die Benutzererfahrung. Dienst-zu-Dienst-Szenarien (d. h. Client Credentials Flow, On-Behalf-Of-Flow) sind ebenfalls betroffen, da das Abrufen eines Tokens von Microsoft Entra ID HTTP-Anfragen erfordert und deutlich langsamer ist als das Abrufen eines Tokens aus dem Cache.

Beachten Sie, dass der Speichercache für serverseitige Anwendungen nicht skalierbar ist und die Leistung beeinträchtigt wird, nachdem einige 100 Token im Cache gespeichert wurden. Bei Web-App- und Web-API-Szenarien entspricht dies einigen 100 Benutzern. Für Daemon-App-Szenarien, die Clientanmeldeinformationen zum Aufrufen anderer Apps verwenden, bedeutet dies einige 100 Mandanten. Weitere Informationen finden Sie unten unter Leistung.

⚠– Es wird empfohlen, den Cache mit Verschlüsselung für alle Produktionsanwendungen sowohl für die Sicherheit als auch für die gewünschte Cachelebensdauer beizubehalten. Wenn Sie den Cache nicht beibehalten möchten, steht die TokenCache-Schnittstelle weiterhin für den Zugriff auf die zwischengespeicherten Entitäten zur Verfügung.

Beständiger Cache

MSAL Node löst Ereignisse aus, wenn auf den Speichercache zugegriffen wird, und Apps können auswählen, ob der Cache beibehalten werden soll (siehe : TokenCacheContext) (z. B. für eine Datei, eine SQL-Datenbank usw.). Dies stellt zwei Aktionen dar:

  1. Laden Sie den Cache aus dem persistenten Speicher in den Arbeitsspeicher von MSAL, bevor Sie auf den Cache zugreifen.
  2. Wenn sich der In-Memory-Cache seit dem letzten Zugriff geändert hat, schreiben Sie den Cache zurück in den persistenten Speicher.

Zum Speichern des Caches akzeptiert MSAL ein benutzerdefiniertes Cache-Plug-In in der Konfiguration. Dieses Plug-In sollte die ICachePlugin-Schnittstelle implementieren:

interface ICachePlugin {
    beforeCacheAccess: (tokenCacheContext: TokenCacheContext) => Promise<void>;
    afterCacheAccess: (tokenCacheContext: TokenCacheContext) => Promise<void>;
}

Eine grundlegende Implementierung der ICachePlugin Schnittstelle kann wie folgt aussehen (siehe auch Leistung und Sicherheit , wenn Sie eine serverseitige App erstellen):

class MyCachePlugin implements ICachePlugin {
    private client: ICacheClient;

    constructor(client: ICacheClient) {
        this.client = client; // client object to access the persistent cache
    }

    public async beforeCacheAccess(cacheContext: TokenCacheContext): Promise<void> {
        const cacheData = await this.client.get(); // get the cache from persistence
        cacheContext.tokenCache.deserialize(cacheData); // deserialize it to in-memory cache
    }

    public async afterCacheAccess(cacheContext: TokenCacheContext): Promise<void> {
        if (cacheContext.cacheHasChanged) {
            await this.client.set(cacheContext.tokenCache.serialize()); // deserialize in-memory cache to persistence
        }
    }
}
  • Wenn Sie eine öffentliche Client-App entwickeln, behandelt MSAL Node Extensions dies für Sie.
  • Wenn Sie eine vertrauliche Client-App entwickeln, sollten Sie den Cache über einen separaten Dienst speichern, da eine einzelne Servercacheinstanz für eine Cloudumgebung mit vielen Servern und App-Instanzen nicht geeignet ist.

Es wird dringend empfohlen, den Tokencache beim Speichern auf dem Datenträger zu verschlüsseln. Für öffentliche Client-Apps wird dies standardmäßig mit MSAL Node Extensions bereitgestellt. Für vertrauliche Clients sind Sie jedoch dafür verantwortlich, eine geeignete Verschlüsselungslösung zu erstellen.

Leistung und Sicherheit

Für öffentliche Client-Apps gewährleistet MSAL Node Extensions für Sie Leistung und Sicherheit.

Bei vertraulichen Client-Apps, die Benutzer verarbeiten (Web-Apps, die Benutzer anmelden und Web-APIs aufrufen, die nachgeschaltete Web-APIs aufrufen), können viele Benutzer gleichzeitig für eine bestimmte Anwendung aktiv sein. Unsere Empfehlung besteht darin, ein Cache-BLOB (siehe CacheRecord) pro Benutzer zu serialisieren. Dies würde dazu beitragen, den Cache über ein verteiltes System zu skalieren. Verwenden Sie einen Schlüssel zum Partitionieren des Caches (z. B.Partitionsschlüssel), z. B.:

  • Für Web-Apps: <userObjectId>.<tenantId> (d. h. homeAccountId)
  • Für mehrinstanzenfähige Daemon-Apps, die den Grant für Clientanmeldeinformationen verwenden: <clientId>.<tenantId>
  • Für Web-APIs, die andere Web-APIs mit OBO aufrufen: Hash des eingehenden Zugriffstokens (d. h. oboAssertion) – das Token, das anschließend gegen ein OBO-Token eingetauscht wird

⚠– Bitte stellen Sie sicher, dass Sie die Leistung sehen, um weitere Informationen zur Überwachung der Nutzung zu finden und eine schlechte Leistung zu vermeiden.

Web-Apps

Da Web-Apps benutzergeschützt sind und häufig auf Sitzungen angewiesen sind, um jeden Benutzer nachzuverfolgen, wird der entsprechende Partitionsschlüssel für die Zwischenspeicherung häufig in den Sitzungsdaten gespeichert und muss abgerufen werden, bevor die Cachesuche stattfinden kann. Um dies zu unterstützen, stellt MSAL Node die DistributedCachePlugin-Klasse bereit, die ICachePlugin implementiert. Eine Instanz von DistributedCachePlugin erfordert:

  • eine Clientschnittstelle (ICacheClient), die get- und set-Operationen auf dem Persistenzserver (Redis, MySQL usw.) implementiert.
  • ein Partitions-Manager (IPartitionManager) zum Lesen und Schreiben in den Cache in Bezug auf eine bestimmte Sitzungs-ID.

Eine Beispielimplementierung finden Sie in der Web-App mit DistributedCachePlugin .

Siehe auch

Weitere Informationen zum Behandeln der Zwischenspeicherung in MSAL Node-Apps finden Sie in den folgenden Beispielen: