Armazenamento em cache de tokens no MSAL Node

Quando o MSAL Node adquire um token, armazena-o em cache para uso futuro. MSAL Node gere a vida útil e a atualização dos tokens para si. APIs como acquireTokenSilent() recuperam tokens de acesso da cache para uma determinada conta:

A MSAL não expõe tokens de atualização por razões de segurança. Consulte as perguntas frequentes para saber como obter os tokens de atualização.

Use os segredos do cliente de forma segura

Os segredos dos clientes nunca devem ser codificados fixamente. O pacote dotenv npm pode ser usado para armazenar segredos num ficheiro .env (localizado na diretoria raiz do projeto) que devem ser incluídos no .gitignore para evitar uploads acidentais dos segredos.

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

Num ambiente de produção, será mais provável que queira serializar e armazenar de forma persistente a cache de tokens. Dependendo do tipo de candidatura, pode:

  • Aplicações de desktop, aplicações de consola (aplicações de clientes públicos (PCA)):
    • Use MSAL Node Extensions, que fornece soluções de persistência e encriptação em repouso no Windows, Linux e Mac OS
  • Aplicações web, APIs web, aplicações daemon (aplicações cliente confidenciais (CCA)):
    • A cache de tokens em memória da MSAL não é escalável para produção. Utilize o padrão de armazenamento em cache distribuído de tokens para persistir a cache no ambiente de armazenamento à sua escolha (Redis, MongoDB, bases de dados SQL, etc. — tenha em mente que pode utilizá-los em conjunto, por exemplo, uma cache de memória do tipo Redis como primeira camada de persistência e uma base de dados SQL como segunda camada de persistência, mais estável)

Cache na memória

O MSAL mantém uma cache em memória. A cache em memória é representativa do estado da cache da aplicação. A vida útil da cache em memória é igual à do objeto de aplicação MSAL. Se o processo que usa MSAL reiniciar, a cache é apagada quando o ciclo de vida do processo termina. Se a cache em memória estiver vazia e não houver cache persistente para restaurar a cache, os utilizadores terão de se autenticar novamente. Quando isto acontece, se o utilizador ainda tiver uma sessão ativa com o Microsoft Entra ID, pode voltar a autenticar-se sem qualquer indicação, mas isso continua a degradar a experiência do utilizador. Os cenários de serviço a serviço (ou seja, fluxo de credenciais do cliente, fluxo em nome de) também são afetados, porque obter um token do Microsoft Entra ID envolve pedidos HTTP e é muito mais lento do que obter um token da memória cache.

Note que a cache em memória não é escalável para aplicações do lado do servidor e o desempenho degrada-se após manter algumas centenas de tokens na cache. Para cenários de aplicações web e APIs web, isto equivale a servir algumas centenas de utilizadores. Para cenários de aplicações do tipo daemon que utilizam o fluxo de credenciais do cliente para invocar outras aplicações, isto significa algumas centenas de locatários. Veja a atuação abaixo para mais informações.

⚠️ Recomendamos fazer a persistência da cache com encriptação em todas as aplicações de produção, tanto por motivos de segurança como para garantir a longevidade pretendida da cache. Se optar por não persistir na cache, a interface do TokenCache continua disponível para aceder às entidades em cache.

Cache persistente

MSAL Node dispara eventos quando a cache em memória é acedida e as aplicações podem escolher se querem persistir a cache (ver: TokenCacheContext) (por exemplo, para um ficheiro, uma base de dados SQL, etc.). Isto constitui duas ações:

  1. Carregue a memória cache do armazenamento persistente para a memória do MSAL antes de aceder à memória cache
  2. Se a cache na memória tiver sido alterada desde o último acesso, grave novamente a cache no armazenamento persistente

Para persistir a cache, o MSAL aceita um plugin de cache personalizado em configuração. Este plugin deve implementar a interface ICachePlugin :

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

Uma implementação básica de ICachePlugin interface pode ser a seguinte (ver também desempenho e segurança se estiver a construir uma aplicação do lado do servidor):

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
        }
    }
}
  • Se está a desenvolver uma aplicação cliente pública, a MSAL Node Extensions trata disto por si.
  • Se está a desenvolver uma aplicação cliente confidencial, deve manter a cache através de um serviço separado, já que uma única instância de cache por servidor não é adequada para um ambiente cloud com muitos servidores e instâncias de aplicação.

Recomendamos fortemente encriptar a cache do token ao mantê-la no disco. Para aplicações cliente públicas, esta funcionalidade é disponibilizada de origem com o MSAL Node Extensions. Para clientes confidenciais, no entanto, é responsável por conceber uma solução de encriptação adequada.

Desempenho e segurança

Em aplicações clientes públicas, as Extensões MSAL Node garantem desempenho e segurança para si.

Em aplicações cliente confidenciais que lidam com utilizadores (aplicações Web que iniciam sessão dos utilizadores e invocam APIs Web, e APIs Web que invocam APIs Web a jusante), podem existir muitos utilizadores ativos em simultâneo numa determinada aplicação. A nossa recomendação é serializar um blob de cache (ver CacheRecord) por utilizador. Isto ajudaria a escalar a cache num sistema distribuído. Use uma chave para particionar a cache (ou seja,chave de partição), tais como:

  • Para aplicações web: <userObjectId>.<tenantId> (ou seja) homeAccountId
  • Para aplicações daemon multicliente que utilizam a concessão de credenciais de cliente: <clientId>.<tenantId>
  • Para APIs Web que chamam outras APIs Web usando OBO: hash do token de acesso de entrada (ou seja, oboAssertion) — o token que será posteriormente trocado por um token OBO

⚠️ Por favor, certifique-se de consultar o desempenho para mais informações sobre como monitorizar a utilização e evitar um desempenho fraco.

Aplicações Web

Como as aplicações web são orientadas para o utilizador e frequentemente dependem de sessões para acompanhar cada utilizador, a chave de partição apropriada para cache é frequentemente armazenada nos dados da sessão e precisa de ser recuperada antes de a pesquisa de cache poder ocorrer. Para ajudar com isto, o MSAL Node fornece a classe DistributedCachePlugin , que implementa o ICachePlugin. Um exemplo de DistributedCachePlugin exige:

  • uma interface de cliente (ICacheClient), que implementa as operações get e set no servidor de persistência (Redis, MySQL, etc.).
  • um gestor de partições (IPartitionManager), para ler da cache e escrever na cache no que diz respeito a um determinado ID de sessão.

Por favor, consulte a aplicação Web usando o DistributedCachePlugin para um exemplo de implementação.

Consulte também

Veja os exemplos abaixo para saber mais sobre como lidar com o cache em aplicações MSAL Node: