Microsoft.Identity.Web のトークン キャッシュ

トークン キャッシュにより、アプリケーションのパフォーマンス、信頼性、およびユーザー エクスペリエンスが向上します。 Microsoft。Identity.Web は、パフォーマンス、永続化、運用の信頼性のバランスを取る柔軟なキャッシュ戦略を提供します。

概要

このセクションでは、Microsoft.Identity.Webがどのトークンをキャッシュするか、そしてなぜキャッシュがアプリケーションにとって重要なのかを説明します。

キャッシュされるトークンは何ですか?

Microsoft。Identity.Web は、いくつかの種類のトークンをキャッシュします。

トークンの種類 サイズ Scope 立ち退き
アクセス トークン 最大 2 KB Per (ユーザー/アプリ、テナント、リソース) 自動 (有効期間ベース)
更新トークン Variable ユーザー アカウントごと 手動またはポリシーベースのアプローチ
ID トークン ~ 2 ~ 7 KB ユーザーあたり 自動

トークン キャッシュが適用される場所:

トークンをキャッシュする理由

パフォーマンス上の利点:

  • Microsoft Entra IDへのラウンド トリップを減らします
  • API 呼び出しの高速化 (L1: <10 ミリ秒対 L2: 最大 30 ミリ秒対ネットワーク: >100 ミリ秒)
  • エンド ユーザーの待機時間の短縮

信頼性の利点:

  • 一時的なMicrosoft Entraの停止中に作業を続行する
  • ネットワークの一時的な障害に対する回復性
  • 分散キャッシュが障害を起こしたときの優雅な劣化

コスト上の利点:

  • 認証要求を減らす (スロットリング回避)
  • 認証操作のAzure コストを削減する

クイック スタート

環境に応じて、次のいずれかのキャッシュ構成をすぐに開始します。

開発 - メモリ内キャッシュ

次の例では、開発とサンプルに適したメモリ内トークン キャッシュを追加します。

using Microsoft.Identity.Web;

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

長所:

  • 設定が簡単
  • 高速パフォーマンス
  • 外部依存関係なし

欠点:

  • アプリの再起動時にキャッシュが失われました。 Web アプリでは、ユーザーは Cookie 経由でサインインしたままですが、アクセス トークンを取得してキャッシュを再作成するには、再サインインする必要があります
  • 運用マルチサーバー展開には適していません
  • アプリケーション インスタンス間で共有されない

生産 - 分散キャッシュ

運用アプリケーション 、特にマルチサーバーデプロイの場合は、Redis または別のプロバイダーによってサポートされる分散キャッシュを使用します。

using Microsoft.Identity.Web;

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

// Choose your cache implementation
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "MyApp_";
});

長所:

  • アプリの再起動後も存続する
  • すべてのアプリケーション インスタンス間で共有
  • L1 + L2 の自動キャッシュ

欠点:

  • 外部キャッシュ インフラストラクチャが必要
  • 追加の構成の複雑さ
  • キャッシュ操作のネットワーク待機時間

キャッシュ戦略の選択

次の決定フローチャートとマトリックスを使用して、デプロイに最適なキャッシュ戦略を選択します。

flowchart TD
    Start([Token Caching<br/>Decision]) --> Q1{Production<br/>Environment?}

    Q1 -->|No - Dev/Test| DevChoice[In-Memory Cache<br/>AddInMemoryTokenCaches]
    Q1 -->|Yes| Q2{Multiple Server<br/>Instances?}

    Q2 -->|No - Single Server| Q3{App Restarts<br/>Acceptable?}
    Q3 -->|Yes| DevChoice
    Q3 -->|No| DistChoice

    Q2 -->|Yes| DistChoice[Distributed Cache<br/>AddDistributedTokenCaches]

    DistChoice --> Q4{Cache<br/>Implementation?}

    Q4 -->|High Performance| Redis[Redis Cache<br/>StackExchange.Redis<br/>⭐ Recommended]
    Q4 -->|Azure Native| Azure[Azure Cache for Redis,<br/>Azure Cosmos DB,<br/>or Azure Database for PostgreSQL]
    Q4 -->|On-Premises| SQL[SQL Server Cache<br/>AddDistributedSqlServerCache]
    Q4 -->|Testing| DistMem[Distributed Memory<br/>Not for production]

    Redis --> L1L2[Automatic L1+L2<br/>Caching]
    Azure --> L1L2
    SQL --> L1L2
    DistMem --> L1L2

    L1L2 --> Config[Configure Options<br/>MsalDistributedTokenCacheAdapterOptions]
    DevChoice --> MemConfig[Configure Memory Options<br/>MsalMemoryTokenCacheOptions]

    style Start fill:#e1f5ff
    style DevChoice fill:#d4edda
    style DistChoice fill:#fff3cd
    style Redis fill:#d1ecf1
    style L1L2 fill:#f8d7da

デシジョン マトリックス

次の表は、一般的なデプロイ シナリオで推奨されるキャッシュの種類をまとめたものです。

シナリオ 推奨されるキャッシュ 根拠
ローカル開発 In-Memory シンプルで、インフラストラクチャは必要ありません
サンプル/デモ In-Memory デモ用の簡単なセットアップ
単一サーバー運用 (再起動 OK) In-Memory セッションを再確立できる場合は許容されます
マルチサーバー運用 Redis 共有キャッシュ、高パフォーマンス、信頼性
Azure ホストされるアプリケーション Azure Cache for Redis ネイティブ Azure統合、マネージド サービス
オンプレミスエンタープライズ SQL Server 既存のインフラストラクチャを活用する
PostgreSQL 環境 PostgreSQL 既存の PostgreSQL データベースを使用し、使い慣れた SQL セマンティクス
セキュリティの高い環境 SQL Server + 暗号化 データ所在地、保存時の暗号化
分散シナリオのテスト 分散メモリ インフラストラクチャを使用せずに L2 キャッシュの動作をテストする

キャッシュの実装

Microsoft。Identity.Web では、いくつかのキャッシュ実装がサポートされています。 インフラストラクチャと可用性の要件に一致するものを選択します。

メモリ内キャッシュ

使用するタイミング:

  • 開発とテスト
  • 許容可能な再起動動作を持つ単一サーバーデプロイ
  • サンプルとプロトタイプ

環境設定:

次のコードは、メモリ内トークン キャッシュを既定の設定に登録します。

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

カスタム オプションの場合:

オプションを渡すことで、有効期限とサイズの制限をカスタマイズできます。

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches(options =>
    {
        // Token cache entry will expire after this duration
        options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);

        // Limit cache size (default is unlimited)
        options.SizeLimit = 500 * 1024 * 1024; // 500 MB
    });

→メモリ内キャッシュの構成の詳細を確認する


自動 L1 をサポートする分散キャッシュ (L2)

使用するタイミング:

  • 本番マルチサーバー展開
  • 再起動後のキャッシュ永続化を必要とするアプリケーション
  • 高可用性のシナリオ

Key feature: Microsoft 以降。Identity.Web v1.8.0 では、分散キャッシュには、パフォーマンスと信頼性のためにメモリ内 L1 キャッシュが自動的に含まれます。

Redis 接続文字列を appsettings.jsonに追加します。

{
  "ConnectionStrings": {
    "Redis": "localhost:6379"
  }
}

次に、分散トークン キャッシュと Redis プロバイダーを Program.csに登録します。

using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders.Distributed;

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

// Redis cache implementation
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "MyApp_"; // Unique prefix per application
});

// Optional: Configure distributed cache behavior
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    // Control L1 cache size
    options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024; // 500 MB

    // Handle L2 cache failures gracefully
    options.OnL2CacheFailure = (exception) =>
    {
        if (exception is StackExchange.Redis.RedisConnectionException)
        {
            // Log the failure
            // Optionally attempt reconnection
            return true; // Retry the operation
        }
        return false; // Don't retry
    };
});

Azure Cache for Redis

Azure Cache for Redisを使用するには、キャッシュをAzure 接続文字列に登録します。

builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("AzureRedis");
    options.InstanceName = "MyApp_";
});

接続文字列の形式:

<cache-name>.redis.cache.windows.net:6380,password=<access-key>,ssl=True,abortConnect=False

SQL Server キャッシュ

次の例では、分散キャッシュ バックエンドとしてSQL Serverを構成します。

builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString("TokenCacheDb");
    options.SchemaName = "dbo";
    options.TableName = "TokenCache";

    // Set expiration longer than access token lifetime (default 1 hour)
    // This prevents cache entries from expiring before tokens
    options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});

Azure Cosmos DB キャッシュ

次の例では、分散キャッシュ バックエンドとしてAzure Cosmos DBを構成します。

builder.Services.AddCosmosCache((CosmosCacheOptions options) =>
{
    options.ContainerName = builder.Configuration["CosmosCache:ContainerName"];
    options.DatabaseName = builder.Configuration["CosmosCache:DatabaseName"];
    options.ClientBuilder = new CosmosClientBuilder(
        builder.Configuration["CosmosCache:ConnectionString"]);
    options.CreateIfNotExists = true;
});

PostgreSQL キャッシュ

Microsoft.Extensions.Caching.Postgres NuGet パッケージが必要です。

appsettings.json:

{
  "ConnectionStrings": {
    "PostgresCache": "Host=localhost;Database=mydb;Username=myuser;Password=mypassword"
  },
  "PostgresCache": {
    "SchemaName": "public",
    "TableName": "token_cache",
    "CreateIfNotExists": true
  }
}

次に、PostgreSQL キャッシュを Program.csに登録します。

builder.Services.AddDistributedPostgresCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString("PostgresCache");
    options.SchemaName = builder.Configuration["PostgresCache:SchemaName"];
    options.TableName = builder.Configuration["PostgresCache:TableName"];
    options.CreateIfNotExists = builder.Configuration.GetValue<bool>("PostgresCache:CreateIfNotExists");
    options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});

→ 分散キャッシュ構成の詳細を確認する


注意事項

セッション ベースのキャッシュには、大きな制限があります。 代わりに分散キャッシュを使用してください。

次の例は、参照用のセッション ベースのトークン キャッシュを示しています。

using Microsoft.Identity.Web.TokenCacheProviders.Session;

// In Program.cs
builder.Services.AddSession();

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddSessionTokenCaches();

// In middleware pipeline
app.UseSession(); // Must be before UseAuthentication()
app.UseAuthentication();
app.UseAuthorization();

Limitations:

  • Cookie サイズの問題 - クレームが多い大きな ID トークンが原因で問題が発生する
  • Scope conflicts - シングルトン TokenAcquisition (Microsoft Graph SDK など) では使用できません
  • セッション アフィニティが必要 - 負荷分散シナリオではうまく機能しない
  • 推奨されません - 代わりに分散キャッシュを使用する

詳細な構成

これらのオプションを使用すると、パフォーマンス、セキュリティ、および削除ポリシーのキャッシュ動作を微調整できます。

L1 キャッシュ制御

L1 (メモリ内) キャッシュは、分散キャッシュを使用する場合のパフォーマンスを向上させます。 次のコードは、L1 キャッシュのサイズと動作を構成します。

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    // Control L1 cache size (default: 500 MB)
    options.L1CacheOptions.SizeLimit = 100 * 1024 * 1024; // 100 MB

    // Disable L1 cache if session affinity is not available
    // (forces all requests to use L2 cache for consistency)
    options.DisableL1Cache = false;
});

L1 を無効にするタイミング:

  • ロード バランサーにセッション アフィニティがない
  • キャッシュの不整合が原因でユーザーが MFA の入力を頻繁に求めるメッセージを表示する
  • トレードオフ: L2 アクセスが遅い (約 30 ミリ秒と最大 10 ミリ秒)

キャッシュ削除ポリシー

削除ポリシーは、キャッシュされたトークンが削除されるタイミングを制御します。 次のコードは、絶対有効期限とスライディング有効期限を設定します。

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    // Absolute expiration (removed after this time, regardless of use)
    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(72);

    // Sliding expiration (renewed on each access)
    options.SlidingExpiration = TimeSpan.FromHours(2);
});

appsettings.json を使用 して削除を構成することもできます。

{
  "TokenCacheOptions": {
    "AbsoluteExpirationRelativeToNow": "72:00:00",
    "SlidingExpiration": "02:00:00"
  }
}
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
    builder.Configuration.GetSection("TokenCacheOptions"));

推奨事項:

  • トークンの 有効期間より長く 有効期限を設定する (トークンは通常、1 時間で期限切れ)
  • 既定値: スライド式有効期限 90 分
  • メモリ使用量とユーザー エクスペリエンスのバランスを取る
  • 考慮: 72 時間の絶対時間 + 2 時間のスライディング時間で良い UX を得る

→ キャッシュ削除戦略の詳細を確認する


静止時の暗号化

分散キャッシュ内の機密トークン データを保護するには、ASP.NET Core Data Protection を使用して暗号化を有効にします。

1 台のマシン

1 台のコンピューターで、組み込みの Data Protection プロバイダーによる暗号化を有効にします。

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.Encrypt = true; // Uses ASP.NET Core Data Protection
});

分散システム (複数のサーバー)

Important

分散システム では、 暗号化キーは既定では共有されません。 キー共有を構成する必要があります。

Azure Key Vault (推奨):

次のコードでは、キーをAzure Blob Storageに保存し、Azure Key Vaultで保護します。

using Microsoft.AspNetCore.DataProtection;

builder.Services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(new Uri(builder.Configuration["DataProtection:BlobUri"]))
    .ProtectKeysWithAzureKeyVault(
        new Uri(builder.Configuration["DataProtection:KeyIdentifier"]),
        new DefaultAzureCredential());

証明書ベース:

次のコードは、ファイル共有にキーを保持し、X.509 証明書で保護します。

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\keys"))
    .ProtectKeysWithCertificate(
        new X509Certificate2("current.pfx", builder.Configuration["CertPassword"]))
    .UnprotectKeysWithAnyCertificate(
        new X509Certificate2("current.pfx", builder.Configuration["CertPassword"]),
        new X509Certificate2("previous.pfx", builder.Configuration["PrevCertPassword"]));

→ 暗号化とデータ保護の詳細


キャッシュのパフォーマンスに関する考慮事項

アプリケーションのキャッシュ容量を計画するには、次の見積もりを使用します。

トークン サイズの見積もり

トークンの種類 一般的なサイズ ごと メモ
アプリ トークン 最大 2 KB テナント × リソース 自動退去
ユーザー トークン 最大 7 KB ユーザー × テナント × リソース 手動による削除が必要
更新トークン Variable User 長命

メモリ計画

3 つの API を呼び出す 500 人の同時ユーザーの場合:

  • ユーザー トークン: 500 × 3 × 7 KB = 10.5 MB
  • オーバーヘッド: 15~20 MB

10,000 人の同時ユーザーの場合:

  • ユーザー トークン: 10,000 × 3 × 7 KB = 210 MB
  • オーバーヘッド: 約300~350 MB

推薦: 予想される同時ユーザーに基づいて、L1 キャッシュ サイズの制限を設定します。

ベスト プラクティス

信頼性が高く効率的なトークン キャッシュを確保するには、次のガイドラインに従ってください。

運用環境で分散キャッシュを使用 する - マルチサーバー展開に不可欠

適切なキャッシュ サイズ制限を設定する - 無制限のメモリの増加を防ぐ

削除ポリシーの構成 - UX とメモリ使用量のバランスを取る

機密データの暗号化を有効にする - 静止データとしてのトークンを保護する

キャッシュの正常性を監視 する - ヒット率、エラー、パフォーマンスを追跡する

L2 キャッシュエラーを適切に処理する - L1 キャッシュは回復性を保証します

テスト キャッシュの動作 - 再起動シナリオとフェールオーバーを確認する

運用環境で分散メモリ キャッシュを使用しない - 非永続的または分散

セッション キャッシュを使用しない - 重大な制限があります

有効期限をトークンの有効期間よりも短く設定しない - 不要な再認証を強制する

暗号化キーの共有を忘れないでください - 分散システムには共有キーが必要です