Buforowanie tokenów w MSAL Node

Gdy węzeł MSAL uzyskuje token, buforuje go w pamięci na potrzeby przyszłego użycia. MSAL Node zarządza cyklem życia tokenu i jego odświeżaniem za Ciebie. Interfejsy API, takie jak acquireTokenSilent(), pobierają tokeny dostępu z pamięci podręcznej dla danego konta:

MSAL nie udostępnia tokenów odświeżania ze względów bezpieczeństwa. Zapoznaj się z często zadawanymi pytaniami , aby uzyskać tokeny odświeżania.

Bezpiecznie używaj kluczy tajnych klienta

Wpisy tajne klienta nigdy nie powinny być zakodowane na stałe. Pakiet npm dotenv może służyć do przechowywania wpisów tajnych w pliku env (znajdującym się w katalogu głównym projektu), który powinien zostać uwzględniony w pliku gitignore , aby zapobiec przypadkowemu przekazaniu wpisów tajnych.

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

W środowisku produkcyjnym najpewniej zechcesz serializować i trwale przechowywać bufor tokenów. W zależności od typu aplikacji można wykonywać następujące czynności:

  • Aplikacje klasyczne, aplikacje konsolowe (publiczne aplikacje klienckie (PCA)):
    • Użyj MSAL Node Extensions, które zapewnia rozwiązania do trwałego przechowywania i szyfrowania danych przechowywanych w systemach Windows, Linux i macOS
  • Aplikacje internetowe, internetowe interfejsy API, aplikacje demona (poufne aplikacje klienckie (CCA)):
    • Pamięć podręczna tokenów w pamięci biblioteki MSAL nie skaluje się w środowisku produkcyjnym. Użyj wzorca rozproszonego buforowania tokenów, aby utrwalać pamięć podręczną w wybranym środowisku magazynowania (Redis, MongoDB, bazy danych SQL itp. — pamiętaj, że można ich używać równolegle, np. pamięci podręcznej podobnej do Redis jako pierwszej warstwy trwałości oraz bazy danych SQL jako drugiej, bardziej stabilnej warstwy trwałości).

Cache w pamięci

Biblioteka MSAL utrzymuje pamięć podręczną w pamięci. Pamięć podręczna w pamięci operacyjnej odzwierciedla stan pamięci podręcznej aplikacji. Czas życia pamięci podręcznej w pamięci jest taki sam jak czas życia obiektu aplikacji MSAL. Jeśli proces korzystający z biblioteki MSAL zostanie ponownie uruchomiony, pamięć podręczna zostanie wyczyszczona po zakończeniu działania procesu. Jeśli pamięć podręczna w pamięci operacyjnej jest pusta i nie ma też trwałej pamięci podręcznej, z której można ją przywrócić, użytkownicy będą musieli ponownie się uwierzytelnić. W takim przypadku, jeśli użytkownik nadal ma aktywną sesję z Microsoft Entra ID, może ponownie uwierzytelnić się bez żadnych monitów, jednak nadal pogarsza to środowisko użytkownika. Scenariusze komunikacji między usługami (tj. przepływ poświadczeń klienta, przepływ w imieniu użytkownika) również stanowią problem, ponieważ pobranie tokenu z usługi Microsoft Entra ID wymaga wysłania żądań HTTP i jest znacznie wolniejsze niż pobranie tokenu z pamięci podręcznej.

Należy pamiętać, że pamięć podręczna w pamięci nie jest skalowalna dla aplikacji po stronie serwera, a wydajność będzie spadać po przechowywaniu kilku 100 tokenów w pamięci podręcznej. W przypadku scenariuszy aplikacji internetowej i internetowego interfejsu API przybliża to obsługę kilku 100 użytkowników. W przypadku scenariuszy aplikacji typu daemon, które używają przepływu poświadczeń klienta do wywoływania innych aplikacji, oznacza to kilkaset dzierżaw. Aby uzyskać więcej informacji, zobacz wydajność poniżej.

⚠✔ Zalecamy utrwalanie pamięci podręcznej z szyfrowaniem dla wszystkich aplikacji produkcyjnych zarówno w celu zapewnienia bezpieczeństwa, jak i żądanej długowieczności pamięci podręcznej. Jeśli zdecydujesz się nie zachowywać pamięci podręcznej, interfejs TokenCache będzie nadal dostępny do uzyskiwania dostępu do obiektów zapisanych w pamięci podręcznej.

Pamięć podręczna trwała

MSAL Node wywołuje zdarzenia, gdy uzyskiwany jest dostęp do pamięci podręcznej w pamięci, a aplikacje mogą zdecydować, czy zachować pamięć podręczną (zobacz: TokenCacheContext) (np. w pliku, bazie danych SQL itp.). Składa się to z dwóch akcji:

  1. Załaduj pamięć podręczną z magazynu trwałego do pamięci biblioteki MSAL przed uzyskaniem dostępu do pamięci podręcznej
  2. Jeśli pamięć podręczna w pamięci zmieniła się od ostatniego dostępu, zapisz pamięć podręczną z powrotem do trwałości

Do trwałego przechowywania pamięci podręcznej biblioteka MSAL obsługuje niestandardową wtyczkę pamięci podręcznej w konfiguracji. Ta wtyczka powinna zaimplementować interfejs ICachePlugin :

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

Podstawowa implementacja interfejsu ICachePlugin może wyglądać następująco (zobacz również wydajność i zabezpieczenia , jeśli tworzysz aplikację po stronie serwera):

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
        }
    }
}
  • Jeśli tworzysz publiczną aplikację kliencką, rozszerzenia biblioteki MSAL Node obsługują to za Ciebie.
  • Jeśli tworzysz poufne aplikacje klienckie, należy zachować pamięć podręczną za pośrednictwem oddzielnej usługi, ponieważ pojedyncze wystąpienie pamięci podręcznej dla serwera nie jest odpowiednie dla środowiska chmury z wieloma serwerami i wystąpieniami aplikacji.

Zdecydowanie zalecamy szyfrowanie pamięci podręcznej tokenów podczas utrwalania jej na dysku. W przypadku publicznych aplikacji klienckich jest to dostępne od razu dzięki rozszerzeniom MSAL Node. Jednak w przypadku klientów poufnych odpowiadasz za opracowanie odpowiedniego rozwiązania do szyfrowania.

Wydajność i zabezpieczenia

W przypadku publicznych aplikacji klienckich rozszerzenia biblioteki MSAL Node zapewniają wydajność i bezpieczeństwo.

W przypadku poufnych aplikacji klienckich obsługujących użytkowników (aplikacje internetowe, które logują użytkowników i wywołujące internetowe interfejsy API oraz internetowe interfejsy API wywołujące podrzędne internetowe interfejsy API), może istnieć wiele użytkowników aktywnych jednocześnie dla danej aplikacji. Zalecamy serializację jednego bloba pamięci podręcznej (zobacz CacheRecord) dla każdego użytkownika. Ułatwiłoby to skalowanie pamięci podręcznej w systemie rozproszonym. Użyj klucza do partycjonowania pamięci podręcznej (tj.klucza partycji), takiego jak:

  • W przypadku aplikacji internetowych: <userObjectId>.<tenantId> (tj. homeAccountId)
  • W przypadku wielodostępnych aplikacji demona korzystających z przepływu poświadczeń klienta: <clientId>.<tenantId>
  • W przypadku internetowych interfejsów API wywołujących inne internetowe interfejsy API przy użyciu OBO: skrót przychodzącego tokenu dostępu (tj. oboAssertion) — tokenu, który następnie zostanie wymieniony na token OBO

⚠️ Aby uzyskać więcej informacji o monitorowaniu wykorzystania i zapobieganiu spadkom wydajności, zapoznaj się z sekcją wydajność.

Aplikacje internetowe

Ponieważ aplikacje internetowe są skierowane do użytkowników i często wykorzystują sesje do śledzenia każdego użytkownika, odpowiedni klucz partycjonowania pamięci podręcznej jest często przechowywany w danych sesji i trzeba go pobrać, zanim będzie można przeprowadzić wyszukiwanie w pamięci podręcznej. W tym celu węzeł MSAL udostępnia klasę DistributedCachePlugin , która implementuje klasę ICachePlugin. Wystąpienie elementu DistributedCachePlugin wymaga:

  • interfejs klienta (ICacheClient), który implementuje operacje get i set na serwerze trwałości (Redis, MySQL itp.).
  • menedżer partycji (IPartitionManager) do odczytu z pamięci podręcznej i zapisywania w pamięci podręcznej w odniesieniu do danego identyfikatora sesji.

Aby zapoznać się z przykładową implementacją, zapoznaj się z aplikacją internetową korzystającą z usługi DistributedCachePlugin .

Zobacz także

Zapoznaj się z poniższymi przykładami, aby uzyskać więcej informacji na temat obsługi buforowania w aplikacjach biblioteki MSAL Node: