Microsoftでのトークン キャッシュの問題を解決します。Identity.Web

この記事は、Microsoftでのトークン キャッシュの問題を診断して解決するのに役立ちます。Identity.Web。 トークン キャッシュの問題により、認証エラー、パフォーマンスの低下、または予期しないサインイン プロンプトが発生する可能性があります。 Microsoftでのトークン キャッシュのしくみの概要について説明します。Identity.Web については、「トークン キャッシュの概要」を参照してください。

前提条件

トラブルシューティングを行う前に、次の内容を確認してください。

トークン キャッシュのログ記録と診断を有効にする

最初の診断手順として詳細なログ記録を有効にします。 Microsoft。Identity.Web は、ASP.NET Core ログ 記録インフラストラクチャを使用し、Microsoft Authentication Library (MSAL) を介してイベントを生成します。

MSAL ログを有効にする

Debug内の ID ライブラリのログ レベルをappsettings.jsonに設定します。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.Identity.Web": "Debug",
      "Microsoft.IdentityModel": "Debug"
    }
  }
}

MSAL キャッシュ イベントを登録する

MSAL トークン キャッシュ通知イベントをサブスクライブして、キャッシュ ヒット、ミス、シリアル化アクティビティを追跡します。

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.OnL2CacheFailure = (ex) =>
    {
        logger.LogWarning(ex, "L2 cache failure encountered.");
        // Return true to allow the operation to continue despite the cache failure.
        // Return false to propagate the exception.
        return true;
    };
});

キャッシュ メトリックの監視

運用環境の監視では、次の主要なメトリックを追跡します。

  • キャッシュ ヒット 率 — ヒット率が低い場合は、トークンがキャッシュから取得されていないことを示します。
  • L2 キャッシュ待機時間 — 待機時間が長い場合は、分散キャッシュ接続またはパフォーマンスの問題が示唆されます。
  • キャッシュのシリアル化エラー — 読み取りまたは書き込み中のエラーは、破損またはバージョンの不一致を示します。
  • メモリ消費量 — 持続的な増加は、削除ポリシーの不足を示す可能性があります。

分散キャッシュ (L2) 接続エラー

症状:

アプリケーション ログには、接続タイムアウト エラーまたは断続的な認証エラーが表示されます。 ユーザーにはサインインの遅延が発生し、次のような例外が表示されます。

Microsoft.Extensions.Caching.StackExchangeRedis.RedisCache:
  StackExchange.Redis.RedisConnectionException: 
  No connection is active/available to service this operation.

または、分散キャッシュSQL Serverの場合:

Microsoft.Data.SqlClient.SqlException:
  A network-related or instance-specific error occurred while 
  establishing a connection to SQL Server.

原因

分散キャッシュ バッキング ストア (Redis または SQL Server) に到達できません。 一般的な原因には、次のようなものがあります。

  • 正しくない接続文字列または期限切れのアクセス資格情報。
  • アプリ ホストからの接続をブロックするネットワーク ファイアウォール規則。
  • キャッシュ サービスが停止しているか、メンテナンス中です。
  • クライアントとキャッシュ サーバーの間の SSL/TLS 構成の不一致。

診断手順

接続エラーを特定するには、次の手順に従います。

  1. 接続を確認します。 アプリケーション ホストから、Test-NetConnection (PowerShell) または redis-cli を使用して、Redis またはSQL Serverへの接続をテストします。
  2. 接続文字列を確認します。 キャッシュ サーバーのホスト名、ポート、資格情報と一致する接続文字列を確認します。
  3. ファイアウォール規則を確認します。 Azureで、アプリ サービスまたは仮想ネットワークがキャッシュ リソースに到達できることを確認します。
  4. サービスの正常性を確認する。 Azure ポータルで、Azure Cache for Redisまたは SQL Database インスタンスの正常性とメトリックを確認します。

ソリューション

手順 1: 接続文字列

appsettings.jsonで接続文字列を確認してください。

{
  "ConnectionStrings": {
    "Redis": "your-redis-instance.redis.cache.windows.net:6380,password=your-access-key,ssl=True,abortConnect=False"
  }
}

Important

Redis 接続文字列で abortConnect=False を設定します。 この設定により、一時的な接続エラーが発生した後、アプリケーションは直ちにスローされるのではなく、自動的に再接続できます。

手順 2: 再試行と回復性を構成する

分散キャッシュが一時的に使用できないときにアプリケーションが正常に低下するように、 OnL2CacheFailure コールバックを構成します。

services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.OnL2CacheFailure = (ex) =>
    {
        // Log the failure for monitoring and alerting.
        logger.LogWarning(ex, "Distributed token cache is unavailable. " +
            "Falling back to in-memory cache.");
        return true; // Continue without the L2 cache.
    };

    // Set a timeout to avoid blocking the request pipeline.
    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12);
});

手順 3: ファイアウォール規則を開く

アプリケーションがAzure App Serviceで実行され、キャッシュが仮想ネットワーク内にある場合は、App Service の送信 IP アドレスをキャッシュ ファイアウォールの許可リストに追加します。

キャッシュの逆シリアル化エラー

症状:

Microsoft.Identity.Web または MSAL.NET をアップグレードした後、アプリケーションは分散キャッシュから読み取る際に逆シリアル化例外を発生させます。 ユーザーはもう一度サインインする必要があり、次のような例外が表示されます。

System.Text.Json.JsonException:
  The JSON value could not be converted to the expected type.

または:

Microsoft.Identity.Client.MsalClientException:
  Error code: json_parse_failed

原因

トークン キャッシュのシリアル化形式がライブラリ バージョン間で変更されました。 以前のバージョンによってキャッシュされたトークンは、新しいバージョンでは逆シリアル化できません。 この問題は、MSAL.NET またはMicrosoftのメジャー バージョンのアップグレード中に最も頻繁に発生します。Identity.Web。

ソリューション

オプション A: キャッシュをクリアする

最も簡単な修正は、分散キャッシュ内のすべてのエントリをクリアすることです。 ユーザーは 1 回再認証し、以降のトークンは新しい形式で書き込まれます。

Redis キャッシュをクリアします。

redis-cli FLUSHDB

または、SQL Server分散キャッシュ テーブルをクリアします。

DELETE FROM [dbo].[TokenCache];

キャッシュをクリアすると、アクティブなすべてのユーザーが再認証されます。 アプリケーションが大規模なユーザー ベースを提供する場合は、メンテナンス期間中にこの操作を計画します。

オプション B: 逆シリアル化エラーを適切に処理する

逆シリアル化エラーを致命的なエラーではなくキャッシュ ミスとして扱うようにキャッシュ アダプターを構成します。

services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.OnL2CacheFailure = (ex) =>
    {
        if (ex is JsonException or MsalClientException)
        {
            logger.LogWarning(ex, "Cache deserialization failed. " +
                "Treating as cache miss.");
            return true;
        }
        return false; // Propagate unexpected errors.
    };
});

この方法では、影響を受けるキャッシュ エントリはユーザーが再認証すると自動的に置き換えられ、手動キャッシュ フラッシュは必要ありません。

サーバー間の暗号化キーの不一致

症状:

分散キャッシュが動作している場合でも、複数インスタンスのデプロイで逆シリアル化エラーが発生します。 あるサーバー インスタンスによってキャッシュされたトークンは、別のサーバー インスタンスが読み取ることはできません。 ログに json_parse_failed エラーまたは IDW10802 エラーが表示されます。

原因

キャッシュ暗号化が有効になっている場合 (options.Encrypt = true)、Microsoft。Identity.Web では、ASP.NET Core Data Protection を使用してキャッシュ エントリを暗号化します。 既定では、各サーバー インスタンスは独自の Data Protection キーを生成するため、1 つのインスタンスは別のインスタンスによって書き込まれたエントリを復号化できません。

ソリューション

ASP.NET Core Data Protection を構成して、すべてのサーバー インスタンス間で暗号化キーを共有します。

Option A: Azure Blob Storage + Azure Key Vault (Azure デプロイに推奨)

using Microsoft.AspNetCore.DataProtection;
using Azure.Identity;

builder.Services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(
        new Uri("https://yourstorageaccount.blob.core.windows.net/dataprotection/keys.xml"),
        new DefaultAzureCredential())
    .ProtectKeysWithAzureKeyVault(
        new Uri("https://yourkeyvault.vault.azure.net/keys/dataprotection-key"),
        new DefaultAzureCredential());

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.Encrypt = true;
});

この構成では、データ保護キー リングがAzure Blob Storageに格納され、保存されているキーがAzure Key Vaultで保護されます。 同じ BLOB とキーにアクセスするすべてのアプリケーション インスタンスは、互いのキャッシュ エントリを暗号化および暗号化解除できます。

オプション B: 証明書保護を使用した共有ファイル システム

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\keys"))
    .ProtectKeysWithCertificate(certificate);

ヒント

データ保護証明書をローテーションするときは、 UnprotectKeysWithAnyCertificate を使用して、現在の証明書と以前の証明書の両方を含めます。 これにより、ローテーション ウィンドウ中に古い証明書で保護されたキーの復号化が可能になります。

メモリ内キャッシュによるメモリの増加

症状:

アプリケーション メモリの消費量は、時間の経過と同時に着実に増加します。 固定メモリ制限があるコンテナーまたは App Service プランでアプリケーションを実行すると、最終的に再起動されるか、 OutOfMemoryExceptionがスローされます。 監視結果では、ガベージ コレクションによる回収が行われないまま、マネージド ヒープが増加していることを示しています。

原因

サイズ制限なしで AddInMemoryTokenCaches() を使用すると、無制限のキャッシュの増加が発生します。 この状況は、各ユーザーのトークン エントリが無期限にメモリを消費するため、多くのユーザーにサービスを提供するアプリケーションでは特に問題になります。

既定では、 MemoryCache は最大サイズを適用せず、有効期限ポリシーが設定されていない限りエントリを削除しません。

ソリューション

オプション A: サイズ制限とスライド式の有効期限を設定する

有効期限ポリシーを使用してメモリ内キャッシュを構成します。

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

services.Configure<MsalMemoryTokenCacheOptions>(options =>
{
    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12);
    options.SlidingExpiration = TimeSpan.FromHours(2);
});

これらの設定では、エントリはアクセスに関係なく 12 時間後に期限切れになり、2 時間アイドル状態のエントリは以前に削除されます。

オプション B: 分散キャッシュに切り替える

同時実行ユーザーが多いアプリケーションの場合、メモリ内キャッシュはスケーリングされません。 Redis などの分散キャッシュに切り替えます。

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = Configuration.GetConnectionString("Redis");
});

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

分散キャッシュは、アプリケーション プロセスからメモリをオフロードし、再起動の間にトークンを保持し、マルチインスタンスデプロイをサポートします。

オプション C: L1/L2 ハイブリッド アーキテクチャを使用する

Microsoft。Identity.Web では、高速のメモリ内 L1 キャッシュと永続的な分散 L2 キャッシュを組み合わせたハイブリッド アプローチがサポートされています。 L1/L2 ハイブリッド キャッシュを構成します。

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.L1CacheOptions = new MsalMemoryTokenCacheOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),
        SlidingExpiration = TimeSpan.FromMinutes(2)
    };
});

L1/L2 キャッシュでは、頻繁にアクセスされるトークンは、ミリ秒未満の待機時間でインメモリ (L1) から提供されます。 L2 キャッシュは、永続化とインスタンス間の一貫性を提供します。 L1 キャッシュは、メモリの増加を制限するために短い有効期限を使用します。

症状:

ユーザーは、最近これらの手順を完了した場合でも、多要素認証 (MFA) または同意を繰り返し求められます。 アプリケーションがキャッシュ内の既存のトークンを見つけることができません。

原因

この問題は、トークン キャッシュ参照がキャッシュされたエントリと現在のユーザー アカウントとの一致に失敗した場合に発生します。 一般的な原因には、次のようなものがあります。

  • キャッシュ キーは、トークンの格納時に使用されるキーとは異なります。 この状況は、 HomeAccountId またはテナント コンテキストが変更された場合に発生する可能性があります。
  • アプリケーションは、メモリ内キャッシュを使用してロード バランサーの背後で複数のインスタンスを実行し、ユーザーのトークンを持たないインスタンスにルートを要求します。
  • 要求された要求またはスコープが変更されたので、キャッシュされたトークンは新しい要件を満たしていません。
  • セッション アフィニティが有効になっていないため、ユーザーはキャッシュされたトークンがない別のインスタンスにルーティングされます。

診断手順

キャッシュにトークンが見つからない理由を特定するには、次の手順に従います。

  1. キャッシュの種類を確認します。 複数インスタンスデプロイで AddInMemoryTokenCaches() を使用する場合、あるインスタンスにキャッシュされたトークンは別のインスタンスでは使用できません。 分散キャッシュに切り替えます。
  2. アカウント識別子を確認します。 デバッグ レベルのログ記録を有効にして、 HomeAccountIdを検索します。 要求間で識別子が一貫していることを確認します。
  3. スコープを調べます。 GetAccessTokenForUserAsyncによって要求されたスコープが、最初に同意したスコープと一致することを確認します。 スコープが一致しない場合、MSAL は新しいトークンを要求します。
  4. 条件付きアクセス ポリシーを確認します。 特定のリソースのステップアップ認証を必要とするMicrosoft Entra ID条件付きアクセス ポリシーでは、キャッシュとは無関係な追加のプロンプトが発生します。

ソリューション

手順 1: 分散キャッシュに切り替える

アプリケーションで複数のインスタンスを実行する場合は、分散キャッシュを使用してインスタンス間でトークンを共有します。

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = Configuration.GetConnectionString("Redis");
});

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

手順 2: 一貫性のあるスコープを確認する

トークンを取得するときに要求するスコープが、認証時に構成されたスコープと一致していることを確認します。

// In authentication setup — initial scopes.
.EnableTokenAcquisitionToCallDownstreamApi(new[] { "User.Read", "Mail.Read" })

// When acquiring a token — use the same scopes.
var token = await tokenAcquisition.GetAccessTokenForUserAsync(
    new[] { "User.Read", "Mail.Read" });

手順 3: セッション アフィニティを有効にする (一時的な回避策)

分散キャッシュにすぐに切り替えることができない場合は、ロード バランサーでセッション アフィニティ (スティッキー セッション) を有効にします。 セッション アフィニティは、ユーザーの要求を同じインスタンスにルーティングします。 この方法は、スケーラビリティの制限を伴う一時的な回避策です。

キャッシュのパフォーマンスの問題

症状:

トークンの取得が遅く、ダウンストリーム API 呼び出しの待機時間が長くなっています。 監視では、トークン取得要求の平均応答時間が高くなります。 待機時間は ID プロバイダーからではなく、トークンはキャッシュから提供されます。

原因

キャッシュのパフォーマンスの問題は、通常、次の結果になります。

  • L2 キャッシュ待機時間が長い。 分散キャッシュは、負荷が高く、アプリケーションから地理的に離れているか、またはサービス レベルが不足しています。
  • 大きなトークン キャッシュ エントリ。 ユーザーごとに多数のリソースのトークンをキャッシュするアプリケーションでは、読み取りと書き込みに時間がかかる大きなシリアル化されたキャッシュ エントリが生成される可能性があります。
  • L1 キャッシュなし。 トークンの取得は、頻繁に使用されるトークンの場合でも、ネットワーク経由で分散キャッシュに送られます。

ソリューション

手順 1: L1 インメモリ キャッシュを有効にする

L1 キャッシュは、頻繁にアクセスされるトークンをプロセス メモリに格納し、L2 へのネットワーク ラウンド トリップを回避します。

services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.L1CacheOptions = new MsalMemoryTokenCacheOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),
        SlidingExpiration = TimeSpan.FromMinutes(2)
    };
});

この構成では、L1 から提供されるトークンの待機時間はミリ秒未満になります。 L1 にないトークンは、L2 分散キャッシュにフォールバックします。

手順 2: 分散キャッシュ層を最適化する

L2 キャッシュの待機時間が長い場合は、次のアクションを検討してください。

  • Redis インスタンスをスケールアップします。 より高いレベル (たとえば、Azure Cache for Redisの Basic から Standard または Premium) に移行して、スループットを向上させ、待機時間を短縮します。
  • ジオレプリケーションを有効にします。 アプリケーションが複数のリージョンのユーザーにサービスを提供する場合は、Azure Cache for Redis geo レプリケーションを使用して、キャッシュが各リージョンのコンピューティングに近づくようにします。
  • ネットワーク構成を確認します。 Private Linkまたは VNet 統合を使用して、アプリケーションとキャッシュの間のネットワーク ホップを減らします。

手順 3: シリアル化されたトークン のサイズを小さくする

トークン キャッシュ エントリが大きい場合は、アプリケーションが必要以上に多くのリソースのトークンを要求するかどうかを確認します。 一意のリソースとスコープの組み合わせごとに、キャッシュ エントリ のサイズが追加されます。 API 呼び出しを可能な限り統合して、ユーザーごとにキャッシュされる個別のアクセス トークンの数を減らします。

Redis Cache の削除

症状:

ユーザーは、トークンの有効期限に基づくパターンなしで、断続的に再認証を求められます。 Redis の監視では、evicted_keysが増加しており、used_memorymaxmemoryの制限に近づいていることが示されています。

原因

Redis は、 maxmemory 制限に達すると、構成された maxmemory-policyに基づいてキーを削除します。 既定のポリシー (volatile-lru) は、有効期限がある、最も最近使用されていないキーを削除します。 Redis インスタンスが他のアプリケーション データと共有されている場合、トークン キャッシュ エントリは領域と競合し、途中で削除される可能性があります。

ソリューション

手順 1: 削除ポリシーを確認する

現在の削除ポリシーを確認します。

redis-cli CONFIG GET maxmemory-policy

トークン キャッシュの場合、トークン キャッシュ エントリの有効期限が切れているため、 volatile-lru (既定値) が適しています。 ただし、有効期限のない他のデータがメモリを消費する場合、トークン エントリは最初に削除されます。

手順 2: 専用 Redis インスタンスを使用する

専用 Redis インスタンスを使用して、他のアプリケーション データからトークン キャッシュを分離します。

{
  "ConnectionStrings": {
    "RedisTokenCache": "token-cache-redis.redis.cache.windows.net:6380,password=...,ssl=True,abortConnect=False",
    "RedisAppData": "app-data-redis.redis.cache.windows.net:6380,password=...,ssl=True,abortConnect=False"
  }
}
// Register the token cache Redis instance specifically for distributed caching.
services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = Configuration.GetConnectionString("RedisTokenCache");
});

手順 3: Redis のメモリ制限を増やす

専用インスタンスが実現できない場合は、 maxmemory 設定を増やします。 Azure Cache for Redisでは、上位レベルにスケールアップするか、キャッシュ サイズを増やします。

手順 4: 適切なキャッシュ エントリの有効期限を設定する

メモリが不足する前に古いエントリが削除されるように、適切な有効期限を設定します。

services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12);
    options.SlidingExpiration = TimeSpan.FromHours(2);
});

SQL 分散キャッシュ テーブルの増加

症状:

SQL 分散キャッシュ テーブルは継続的に拡張され、ディスク領域が消費されます。 キャッシュ テーブルに対するデータベース クエリは時間の経過と同時に遅くなり、テーブル のサイズまたはストレージの制限に関する警告が表示される場合があります。

原因

SQL Server分散キャッシュ (Microsoft.Extensions.Caching.SqlServer) は、期限切れのエントリを自動的に削除しません。 期限切れのエントリは明示的に消去されるまで保持され、無制限のテーブルの増加、クエリ パフォーマンスの低下、ストレージの消費の原因となります。

ソリューション

手順 1: 定期的なクリーンアップ ジョブを設定する

SQL Server エージェント ジョブまたはスケジュールされたタスクを作成して、期限切れのエントリを定期的に削除します。

-- Delete expired entries from the SQL distributed cache table.
-- Schedule this query to run every 30 minutes.
DELETE FROM [dbo].[TokenCache]
WHERE ExpiresAtTime < GETUTCDATE();

ヒント

SQL Server エージェントが使用できないAzure SQL Databaseでは、Azure Automation、タイマー トリガーを使用したAzure Functions、またはエラスティック ジョブを使用してクリーンアップをスケジュールします。

手順 2: 効率的なクリーンアップのためのインデックスを追加する

キャッシュ テーブルに有効期限列のインデックスがまだない場合は、削除操作を高速化するためにインデックスを追加します。

CREATE NONCLUSTERED INDEX IX_TokenCache_ExpiresAtTime
ON [dbo].[TokenCache] (ExpiresAtTime);

手順 3: テーブル のサイズを監視する

監視を追加して、一定期間の行数とテーブル サイズを追跡します。

SELECT
    COUNT(*) AS TotalEntries,
    COUNT(CASE WHEN ExpiresAtTime < GETUTCDATE() THEN 1 END) AS ExpiredEntries,
    COUNT(CASE WHEN ExpiresAtTime >= GETUTCDATE() THEN 1 END) AS ActiveEntries
FROM [dbo].[TokenCache];

手順 4: Redis への切り替えを検討する

SQL キャッシュのクリーンアップの管理が面倒な場合は、組み込みの TTL メカニズムを使用して有効期限を自動的に処理する Redis に切り替えます。

// Replace SQL distributed cache with Redis.
services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = Configuration.GetConnectionString("Redis");
});

一般的なトラブルシューティングのヒント

問題がこの記事の特定のシナリオと一致しない場合は、次のヒントを使用します。

キャッシュが使用されていることを確認する

トークンの読み取りとキャッシュへの書き込みを確認するための一時的なログ記録を追加します。

services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.Encrypt = false; // Disable encryption temporarily for debugging only.
    options.OnL2CacheFailure = (ex) =>
    {
        logger.LogError(ex, "L2 cache operation failed.");
        return true;
    };
});

複数のキャッシュ登録を確認する

スタートアップ コードに AddInMemoryTokenCaches() または AddDistributedTokenCaches() の呼び出しが複数存在する場合は、最後の登録が優先されます。 1 つのキャッシュの種類のみが登録されていることを確認します。

トークンの有効期間を確認する

アクセス トークンの有効期間は有限です (通常は 60 ~ 90 分)。 この期間が経過した後にユーザーが再認証を報告した場合、キャッシュの問題ではなく動作が予想されます。 更新トークンは、新しいアクセス トークンを自動的に取得し、キャッシュに格納されます。 更新トークンが見つからないか有効期限が切れている場合、ユーザーは再認証する必要があります。

クリーン キャッシュを使用してテストする

問題を診断するときは、キャッシュをクリアして、破損したエントリまたは古いエントリを除外します。

  • メモリ内キャッシュ: アプリケーションを再起動します。
  • Redis: キャッシュ データベースで FLUSHDB を実行します。
  • SQL Server: キャッシュ テーブルからすべての行を削除します。

アプリケーションの再起動後にトークン キャッシュが空になる

症状:

ユーザーは、アプリケーションの再起動または再デプロイのたびに再認証する必要があります。 分散キャッシュが空であるか、トークンが永続化されていないように見えます。

原因

この問題は通常、運用環境でメモリ内キャッシュ (AddInMemoryTokenCaches()) または非永続的分散メモリ キャッシュ (AddDistributedMemoryCache()) を使用する場合に発生します。 どちらのオプションも、アプリケーションの再起動中にトークンを保持しません。

AddDistributedMemoryCache() は、データをメモリに格納する IDistributedCache 実装を登録します。 "分散" 名にもかかわらず、データは外部に保持されないため、開発とテストのみを目的としています。

ソリューション

永続的な分散キャッシュに切り替えます。

// Register a persistent cache (Redis example).
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "MyApp_";
});

// Use distributed token caches instead of in-memory.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

Warnung

AddDistributedMemoryCache()と永続的な分散キャッシュを混同しないでください。 運用ワークロードには、AddStackExchangeRedisCache() (Redis)、AddDistributedSqlServerCache() (SQL Server)、または別の永続的な IDistributedCache 実装を使用します。