Сериализация кэша маркеров в MSAL.NET

Библиотека аутентификации Майкрософт (MSAL) кэширует каждый полученный маркер. Общедоступные клиентские приложения (настольные и мобильные) должны попытаться получить маркер из кэша, прежде чем получать его другим способом. Методы получения маркеров в конфиденциальных клиентских приложениях управляют кэшем самостоятельно. В этой статье рассматриваются стандартная и пользовательская сериализации для кэша маркеров в MSAL.NET.

Краткая сводка

Рекомендации

  • При написании классического приложения используйте кроссплатформенный кэш маркеров, как описано в настольных приложениях.
  • Ничего не делайте в мобильных и UWP-приложений. MSAL.NET предоставляет защищенное хранилище для кэша.
  • Для веб-приложений и веб-API используйте Microsoft.Identity.Web в качестве API более высокого уровня в ASP.NET Core. Вы получите кэши маркеров и многое другое. См. статью Веб-приложения и веб-API ASP.NET Core.
  • В других вариантах веб-приложений и веб-API:
    • если вы запрашиваете маркеры для пользователей в рабочем приложении, используйте кэш распределенных маркеров (Redis, SQL Server, Azure Cosmos DB, распределенную память). Используйте сериализаторы кэша маркеров из Microsoft.Identity.Web.TokenCache.
    • В противном случае, если вы хотите использовать кэш в памяти:
      • Если вы используете только AcquireTokenForClient, то либо повторно используйте экземпляр конфиденциального клиентского приложения, не добавляя сериализатор, либо создайте новое конфиденциальное клиентское приложение и включите опцию общего кэша.

        Общий кэш выполняется быстрее, так как он не сериализуется. Однако память будет увеличиваться по мере кэширования маркеров. Количество маркеров равно количеству клиентов, умноженному на число нижестоящих API. Размер маркера приложения составляет около 2 КБ, тогда как маркеры пользователя имеют размер около 7 КБ. Это очень удобно для разработки, или если у вас несколько пользователей.

      • Если вы хотите использовать кэш маркеров в памяти и управлять его размерами и политиками вытеснения, используйте параметр кэширования Microsoft.Identity.Web в памяти.

  • Если вы создаете пакет SDK и хотите написать собственный сериализатор кэша маркеров для конфиденциальных клиентских приложений, наследуйте его от Microsoft.Identity.Web.MsalAbstractTokenCacheProvider и переопределите методы WriteCacheBytesAsync и ReadCacheBytesAsync.

Пакет NuGet Microsoft.Identity.Web.TokenCache обеспечивает сериализацию кэша маркеров в библиотеке Microsoft.Identity.Web.

Метод расширения Описание
AddInMemoryTokenCaches Создает временный кэш в памяти для хранения и извлечения маркеров. Кэши маркеров в памяти выполняются быстрее, чем другие типы кэша, но их маркеры не сохраняются при перезапусках приложений, и вы не можете управлять размером кэша. Кэши в памяти подходят для приложений, которые не нуждаются в сохранении маркеров при перезапусках приложений. Используйте кэш маркеров в памяти в приложениях, которые участвуют в сценариях проверки подлинности между компьютерами, таких как службы, управляющие программы и другие, использующие AcquireTokenForClient (предоставление учетных данных клиента). Кэши маркеров в памяти также подходят для образцов приложений и во время разработки локальных приложений. Microsoft.Identity.Web версий 1.19.0+ совместно использует кэш маркеров в памяти для всех экземпляров приложения.
AddSessionTokenCaches Кэш маркеров привязан к сеансу пользователя. Этот вариант неидеален, если маркер идентификатора содержит много утверждений, так как файл cookie становится слишком большим.
AddDistributedTokenCaches Кэш маркеров является адаптером для реализации IDistributedCache ASP.NET Core. Он позволяет выбирать между кэшем распределенной памяти, кэшем Redis, распределенным кэшем NCache или кэшем SQL Server. Дополнительные сведения о реализациях IDistributedCache см. в статье Кэш распределенной памяти.

Кэш маркеров в памяти

Ниже приведен пример кода с использованием кэша в памяти в методе ConfigureServices класса Startup в приложении ASP.NET Core:

#using Microsoft.Identity.Web
using Microsoft.Identity.Web;

public class Startup
{
 const string scopesToRequest = "user.read";
  
  public void ConfigureServices(IServiceCollection services)
  {
   // code before
   services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
           .AddMicrosoftIdentityWebApp(Configuration)
             .EnableTokenAcquisitionToCallDownstreamApi(new string[] { scopesToRequest })
                .AddInMemoryTokenCaches();
   // code after
  }
  // code after
}

AddInMemoryTokenCaches подходит для рабочей среды, если вы запрашиваете маркеры только для приложений. Если вы используете маркеры пользователя, рассмотрите возможность использования распределенного кэша маркеров.

Код конфигурации кэша маркеров аналогичен для веб-приложений и веб-API ASP.NET Core.

Распределенные кэши маркеров

Вот несколько примеров распределенных кэшей:

// or use a distributed Token Cache by adding
   services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
           .AddMicrosoftIdentityWebApp(Configuration)
             .EnableTokenAcquisitionToCallDownstreamApi(new string[] { scopesToRequest }
               .AddDistributedTokenCaches();

// Distributed token caches have a L1/L2 mechanism.
// L1 is in memory, and L2 is the distributed cache
// implementation that you will choose below.
// You can configure them to limit the memory of the 
// L1 cache, encrypt, and set eviction policies.
services.Configure<MsalDistributedTokenCacheAdapterOptions>(options => 
  {
    // Optional: Disable the L1 cache in apps that don't use session affinity
    //                 by setting DisableL1Cache to 'false'.
    options.DisableL1Cache = false;
    
    // Or limit the memory (by default, this is 500 MB)
    options.L1CacheOptions.SizeLimit = 1024 * 1024 * 1024, // 1 GB

    // You can choose if you encrypt or not encrypt the cache
    options.Encrypt = false;

    // And you can set eviction policies for the distributed
    // cache.
    options.SlidingExpiration = TimeSpan.FromHours(1);
  }

// Then, choose your implementation of distributed cache
// -----------------------------------------------------

// good for prototyping and testing, but this is NOT persisted and it is NOT distributed - do not use in production
services.AddDistributedMemoryCache();

// Or a Redis cache
// Requires the Microsoft.Extensions.Caching.StackExchangeRedis NuGet package
services.AddStackExchangeRedisCache(options =>
{
 options.Configuration = "localhost";
 options.InstanceName = "SampleInstance";
});

// You can even decide if you want to repair the connection
// with Redis and retry on Redis failures. 
services.Configure<MsalDistributedTokenCacheAdapterOptions>(options => 
{
  options.OnL2CacheFailure = (ex) =>
  {
    if (ex is StackExchange.Redis.RedisConnectionException)
    {
      // action: try to reconnect or something
      return true; //try to do the cache operation again
    }
    return false;
  };
});

// Or even a SQL Server token cache
// Requires the Microsoft.Extensions.Caching.SqlServer NuGet package
services.AddDistributedSqlServerCache(options =>
{
 options.ConnectionString = _config["DistCache_ConnectionString"];
 options.SchemaName = "dbo";
 options.TableName = "TestCache";
});

// Or an Azure Cosmos DB cache
// Requires the Microsoft.Extensions.Caching.Cosmos NuGet package
services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
    cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
    cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
    cacheOptions.ClientBuilder = new CosmosClientBuilder(Configuration["CosmosConnectionString"]);
    cacheOptions.CreateIfNotExists = true;
});

Дополнительные сведения см. в разделе:

Использование распределенного кэша описано в руководстве по веб-приложению ASP.NET Core, этап Кэш маркеров 2-2.

Мониторинг коэффициентов попаданий в кэш и производительности кэша

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

Метрика Значение Когда следует запускать оповещение?
DurationTotalInMs Общее время, затраченное на MSAL, включая сетевые вызовы и кэш. Оповещение при общей высокой задержке (> 1 с). Значение зависит от источника маркера. Из кэша: один доступ к кэшу. Из Azure Active Directory (Azure AD): два доступа к кэшу и один вызов HTTP. Самый первый вызов (для каждого процесса) займет больше времени из-за одного дополнительного вызова HTTP.
DurationInCacheInMs Время, затраченное на загрузку или сохранение кэша маркеров, настраиваемое разработчиком приложения (например, сохранение в Redis). Предупреждение при пиках.
DurationInHttpInMs Время, затраченное на выполнение HTTP-вызовов к Azure AD. Предупреждение при пиках.
TokenSource Источник маркера. Маркеры извлекаются из кэша гораздо быстрее (например, ~ 100 мс по сравнению с ~ 700 мс). Может использоваться для отслеживания коэффициента попадания в кэш и соответствующих оповещений. Использовать с DurationTotalInMs.
CacheRefreshReason Причина получения маркера доступа от поставщика удостоверений. Использовать с TokenSource.

Дальнейшие действия

Приведенные ниже примеры демонстрируют сериализацию кэша маркеров.

Образец Платформа Описание
active-directory-dotnet-desktop-msgraph-v2 Классическое приложение (WPF) Классическое приложение .NET (WPF) для Windows, вызывающее API-интерфейс Microsoft Graph. Diagram that shows a topology with a desktop app client flowing to Azure Active Directory by acquiring a token interactively and to Microsoft Graph.
active-directory-dotnet-v1-to-v2 Классическое приложение (консольное) Набор решений Visual Studio, иллюстрирующий перенос приложений Azure AD версии 1.0 (с помощью ADAL.NET) в приложения платформы удостоверений Майкрософт (с помощью MSAL.NET). В частности см. статьи Миграция кэша маркеров и Кэш маркеров конфиденциального клиента.
ms-identity-aspnet-webapp-openidconnect ASP.NET (net472) Пример сериализации кэша маркеров в приложении MVC ASP.NET (с использованием MSAL.NET). В частности, см. статью MsalAppBuilder.