Кэширование токенов в MSAL Node

Когда узел MSAL получает токен, он кэширует его в памяти для дальнейшего использования. MSAL Node управляет сроком действия токена и его обновлением за вас. API, такие как acquireTokenSilent(), извлекают токены доступа из кэша для указанной учетной записи:

MSAL не предоставляет доступ к токенам обновления по соображениям безопасности. Ознакомьтесь с часто задаваемыми вопросами о том, как получить маркеры обновления.

Безопасное использование секретов клиента

Секреты клиента никогда не должны быть жестко закодированы. Пакет dotenv npm можно использовать для хранения секретов в env-файле (расположенном в корневом каталоге проекта), который должен быть включен в gitignore , чтобы предотвратить случайные отправки секретов.

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

В рабочей эксплуатации вам, вероятно, потребуется сериализовать и сохранить кэш токенов. В зависимости от типа приложения можно:

  • Настольные приложения, консольные приложения (общедоступные клиентские приложения (PCA)):
    • Использование расширений узлов MSAL, которые обеспечивают сохраняемость и шифрование неактивных решений на Windows, Linux и Mac OS
  • Веб-приложения, веб-API, приложения управляющей программы (конфиденциальные клиентские приложения (CCA)):
    • Кэш токенов MSAL в памяти не подходит для промышленной эксплуатации. Используйте шаблон распределённого кэширования токенов, чтобы сохранять кэш в выбранной вами среде хранения (Redis, MongoDB, базы данных SQL и т. д. — имейте в виду, что их можно использовать совместно: например, кэш в памяти наподобие Redis в качестве первого уровня хранения и базу данных SQL в качестве второго, более стабильного уровня хранения).

Кэш в памяти

MSAL поддерживает кэш в памяти. Кэш в памяти представляет состояние кэша приложений. Время существования кэша в памяти совпадает с объектом приложения MSAL. Если процесс с помощью MSAL перезапускается, кэш удаляется после завершения жизненного цикла процесса. Если кэш в памяти пуст и не существует постоянного кэша для восстановления кэша, пользователям придется повторно пройти проверку подлинности. Если пользователь по-прежнему имеет активный сеанс с Microsoft Entra ID, он может повторно пройти проверку подлинности без каких-либо запросов, однако это по-прежнему ухудшает взаимодействие с пользователем. Межсервисные сценарии (то есть поток учетных данных клиента и поток "от имени пользователя") тоже работают хуже, поскольку получение токена из Microsoft Entra ID требует HTTP-запросов и занимает значительно больше времени, чем получение токена из кэша.

Обратите внимание, что кэш в памяти не масштабируется для серверных приложений и производительность будет ухудшаться после хранения нескольких 100 маркеров в кэше. Для сценариев веб-приложения и веб-API это приблизилось к обслуживанию нескольких 100 пользователей. Для сценариев управления приложениями, использующих учетные данные клиента для вызова других приложений, это означает несколько 100 клиентов. Дополнительные сведения см. в разделе о производительности ниже.

⚠️ Мы рекомендуем сохранить кэш с шифрованием для всех рабочих приложений как для обеспечения безопасности, так и для требуемого долголетия кэша. Если вы решили не сохранять кэш, интерфейс TokenCache по-прежнему доступен для доступа к кэшируемым сущностям.

Постоянный кэш

MSAL Node запускает события, когда доступ к кэшу в памяти осуществляется, и приложения могут выбрать, следует ли сохранять кэш (см.: TokenCacheContext) (например, в файл, базу данных SQL и т. д.). Это два действия:

  1. Загрузить кэш из постоянного хранилища в память MSAL перед обращением к кэшу
  2. Если кэш в памяти изменился с момента последнего доступа, сохраните кэш обратно в сохраняемость.

Для сохранения кэша MSAL поддерживает пользовательский подключаемый модуль кэша в configuration. Этот подключаемый модуль должен реализовать интерфейс ICachePlugin :

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

Базовая реализация ICachePlugin интерфейса может выглядеть следующим образом (см. также производительность и безопасность при создании серверного приложения):

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
        }
    }
}
  • Если вы разрабатываете общедоступное клиентское приложение, расширения узлов MSAL обрабатывают это для вас.
  • Если вы разрабатываете конфиденциальное клиентское приложение, необходимо сохранить кэш через отдельную службу, так как один экземпляр кэша на сервере не подходит для облачной среды с множеством серверов и экземпляров приложений.

Настоятельно рекомендуется зашифровать кэш маркеров при сохранении его на диске. Для публичных клиентских приложений это доступно из коробки в MSAL Node Extensions. Однако для конфиденциальных клиентов вы несете ответственность за разработку соответствующего решения шифрования.

Производительность и безопасность

В общедоступных клиентских приложениях расширения узлов MSAL обеспечивают производительность и безопасность.

В конфиденциальных клиентских приложениях, работающих с пользователями (веб-приложениях, в которых пользователи входят в систему и которые вызывают веб-API, а также веб-API, вызывающих нижестоящие веб-API), для одного приложения может одновременно быть активно множество пользователей. Наша рекомендация заключается в сериализации одного большого двоичного объекта кэша (см. раздел CacheRecord) для каждого пользователя. Это поможет с масштабированием кэша в распределенной системе. Используйте ключ для секционирования кэша (т. е.ключа секции), например:

  • Для веб-приложений: <userObjectId>.<tenantId> (т. е. homeAccountId)
  • Для мультитенантных приложений-демонов, использующих предоставление учетных данных клиента: <clientId>.<tenantId>
  • Для веб-API, вызывающих другие веб-API с помощью OBO: хэш входящего токена доступа (т. е. oboAssertion) — токена, который впоследствии будет обменян на токен OBO

⚠️ Убедитесь, что вы увидите производительность для получения дополнительных сведений о том, как отслеживать использование и избегать низкой производительности.

Веб-приложения

Поскольку веб-приложения ориентированы на пользователей и часто используют сеансы для отслеживания действий каждого пользователя, соответствующий ключ раздела для кэширования часто хранится в данных сеанса, и его необходимо получить до выполнения поиска в кэше. Чтобы помочь с этим, MSAL Node предоставляет класс DistributedCachePlugin , который реализует ICachePlugin. Для экземпляра DistributedCachePlugin требуется:

  • клиентский интерфейс (ICacheClient), который реализует операции get и set на сервере хранения данных (Redis, MySQL и т. д.).
  • Диспетчер секций (IPartitionManager) для чтения и записи в кэш с учетом заданного идентификатора сеанса.

Ознакомьтесь с веб-приложением с помощью DistributedCachePlugin для примера реализации.

См. также

Дополнительные сведения об обработке кэширования в приложениях MSAL Node см. в приведенных ниже примерах.