Cache token di Microsoft.Identity.Web

Cache token meningkatkan performa aplikasi, keandalan, dan pengalaman pengguna. Microsoft.Identity.Web menyediakan strategi penembolokan fleksibel yang menyeimbangkan performa, persistensi, dan keandalan operasional.

Ikhtisar

Bagian ini menjelaskan token mana yang disimpan sementara oleh Microsoft.Identity.Web dan mengapa penyimpanan sementara penting untuk aplikasi Anda.

Token apa yang di-cache?

Microsoft. Identity.Web menyimpan beberapa jenis token:

Jenis Token Ukuran Ruang lingkup Penggusuran
Token Akses ~2 KB Per (pengguna/aplikasi, penyewa, sumber daya) Otomatis (berbasis seumur hidup)
Refresh Token Variabel Per akun pengguna Berbasis manual atau kebijakan
Token Identifikasi ~2-7 KB Per pengguna Otomatis

Tempat penembolokan token berlaku:

Mengapa token cache?

Keuntungan Performa:

  • Mengurangi perjalanan pulang pergi ke Microsoft Entra ID
  • Panggilan API yang lebih cepat (L1: <10ms vs L2: ~30ms vs jaringan: >100ms)
  • Latensi yang lebih rendah untuk pengguna akhir

Manfaat Keandalan:

  • Terus bekerja selama pemadaman Microsoft Entra sementara
  • Tahan terhadap gangguan jaringan sementara
  • Degradasi yang anggun saat cache terdistribusi gagal

Keuntungan Biaya:

  • Mengurangi permintaan autentikasi (menghindari pembatasan)
  • Biaya Azure yang lebih rendah untuk operasi autentikasi

Mulai Cepat

Mulai dengan cepat menggunakan salah satu konfigurasi cache berikut, tergantung pada lingkungan Anda.

Pengembangan - Cache dalam Memori

Contoh berikut menambahkan cache token dalam memori, cocok untuk pengembangan dan sampel:

using Microsoft.Identity.Web;

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

Keuntungan:

  • Pengaturan sederhana
  • Performa cepat
  • Tidak ada dependensi eksternal

Kekurangan:

  • Cache hilang saat menghidupkan ulang aplikasi. Di aplikasi web, pengguna tetap masuk melalui cookie tetapi harus masuk kembali untuk mendapatkan token akses dan mengisi ulang cache
  • Tidak cocok untuk implementasi produksi multi-server
  • Tidak dibagikan di seluruh instans aplikasi

Produksi - cache terdistribusi

Untuk aplikasi produksi, terutama penyebaran multi-server, gunakan cache terdistribusi yang didukung oleh Redis atau penyedia lain:

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

Keuntungan:

  • Bertahan setelah aplikasi dihidupkan ulang
  • Dibagikan di semua instance aplikasi
  • Cache L1+L2 otomatis

Kekurangan:

  • Memerlukan infrastruktur cache eksternal
  • Kompleksitas konfigurasi tambahan
  • Latensi jaringan untuk operasi cache

Memilih strategi cache

Gunakan diagram alur keputusan dan matriks berikut untuk memilih strategi cache yang paling sesuai dengan penyebaran Anda.

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

Matriks keputusan

Tabel berikut ini meringkas jenis cache yang direkomendasikan untuk skenario penyebaran umum.

Skenario Cache yang Direkomendasikan Alasan
Pengembangan lokal In-Memory Kesederhanaan, tidak ada infrastruktur yang diperlukan
Sampel/demo In-Memory Penyiapan mudah untuk demonstrasi
Produksi server tunggal (mulai ulang OK) In-Memory Dapat diterima jika sesi dapat dibuat ulang
Produksi multi-server Redis Cache bersama, performa tinggi, andal
aplikasi yang dihosting Azure Azure Cache for Redis Integrasi Azure asli, layanan terkelola
Perusahaan lokal SQL Server Memanfaatkan infrastruktur yang ada
Lingkungan PostgreSQL PostgreSQL Menggunakan database PostgreSQL yang ada, semantik SQL yang sudah dikenal
Lingkungan keamanan tinggi SQL Server + Enkripsi Residensi data, enkripsi saat tidak aktif
Menguji skenario terdistribusi Memori Terdistribusi Menguji perilaku cache L2 tanpa infrastruktur

Implementasi cache

Microsoft. Identity.Web mendukung beberapa implementasi cache. Pilih salah satu yang cocok dengan persyaratan infrastruktur dan ketersediaan Anda.

Cache dalam memori

Kapan menggunakan:

  • Pengembangan dan pengujian
  • Penyebaran server tunggal dengan perilaku hidupkan ulang yang dapat diterima
  • Sampel dan prototipe

Configuration:

Kode berikut mendaftarkan cache token dalam memori dengan pengaturan default:

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

Dengan opsi kustom:

Anda dapat menyesuaikan batas kedaluwarsa dan ukuran dengan menentukan opsi:

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

→ Pelajari selengkapnya tentang konfigurasi cache dalam memori


Cache terdistribusi (L2) dengan dukungan L1 otomatis

Kapan menggunakan:

  • Penyebaran multi-server lingkungan produksi
  • Aplikasi yang memerlukan persistensi cache saat restart
  • Skenario ketersediaan tinggi

Fitur utama: Sejak Microsoft.Identity.Web v1.8.0, cache terdistribusi secara otomatis menyertakan cache L1 dalam memori untuk meningkatkan performa dan keandalan.

Tambahkan string koneksi Redis ke appsettings.json:

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

Kemudian daftarkan cache token terdistribusi dan penyedia Redis di 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

Untuk menggunakan Azure Cache for Redis, daftarkan cache dengan Azure string koneksi Anda:

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

Format string koneksi:

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

SQL Server tembolok

Contoh berikut mengonfigurasi SQL Server sebagai backend cache terdistribusi:

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

Cache Azure Cosmos DB

Contoh berikut mengonfigurasi Azure Cosmos DB sebagai backend cache terdistribusi:

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

Cache PostgreSQL

Memerlukan paket NuGet Microsoft.Extensions.Caching.Postgres.

appsettings.json:

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

Kemudian daftarkan cache PostgreSQL di 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);
});

→ Pelajari selengkapnya tentang konfigurasi cache terdistribusi


Perhatian

Penembolokan berbasis sesi memiliki batasan yang signifikan. Gunakan cache terdistribusi sebagai gantinya.

Contoh berikut menunjukkan cache token berbasis sesi sebagai referensi.

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:

  • Masalah ukuran cookie - Token ID besar dengan banyak klaim menyebabkan masalah
  • Konflik Lingkup - Tidak dapat digunakan bersama dengan singleton TokenAcquisition (misalnya, Microsoft Graph SDK)
  • Afinitas sesi diperlukan - Tidak berfungsi dengan baik dalam skenario penyeimbangan beban
  • Tidak disarankan - Gunakan cache terdistribusi sebagai gantinya

Konfigurasi tingkat lanjut

Opsi ini memungkinkan Anda menyempurnakan perilaku cache untuk kebijakan performa, keamanan, dan pengeluaran.

Kontrol L1 cache

Cache L1 (dalam memori) meningkatkan performa saat Anda menggunakan cache terdistribusi. Kode berikut mengonfigurasi ukuran dan perilaku cache 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;
});

Kapan harus menonaktifkan L1:

  • Tidak ada afinitas sesi dalam penyeimbang beban (load balancer)
  • Pengguna sering kali diminta untuk Autentikasi Multi-Faktor karena inkonsistensi cache
  • Trade-off: Kecepatan akses L2 lebih rendah (~30ms vs ~10ms)

Kebijakan pengeluaran cache

Kebijakan pengeluaran mengontrol kapan token yang di-cache dihapus. Kode berikut ini menetapkan kedaluwarsa absolut dan kedaluwarsa geser:

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

Anda juga dapat mengonfigurasi pengeluaran melalui appsettings.json:

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

Recommendations:

  • Atur kedaluwarsa lebih lama dari masa pakai token (token biasanya kedaluwarsa dalam 1 jam)
  • Default: Kedaluwarsa tergeser 90 menit
  • Keseimbangan antara penggunaan memori dan pengalaman pengguna
  • Pertimbangkan: 72 jam tetap + 2 jam fleksibel demi UX yang optimal

→ Pelajari selengkapnya tentang strategi pengeluaran cache


Enkripsi saat tidak aktif

Untuk melindungi data token sensitif dalam cache terdistribusi, aktifkan enkripsi melalui ASP.NET Core Perlindungan Data.

Mesin tunggal

Pada satu komputer, aktifkan enkripsi dengan penyedia Perlindungan Data bawaan:

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

Sistem terdistribusi (beberapa server)

Penting

Sistem terdistribusi tidak berbagi kunci enkripsi secara default. Anda harus mengonfigurasi berbagi kunci:

Azure Key Vault (disarankan):

Kode berikut mempertahankan kunci untuk Azure Blob Storage dan melindunginya dengan 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());

Berbasis sertifikat:

Kode berikut mempertahankan kunci ke berbagi file dan melindunginya dengan sertifikat 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"]));

→ Pelajari selengkapnya tentang enkripsi dan perlindungan data


Pertimbangan performa cache

Gunakan perkiraan berikut untuk merencanakan kapasitas cache untuk aplikasi Anda.

Perkiraan ukuran token

Jenis Token Ukuran Umum Per Catatan
Token aplikasi ~2 KB Sumber Daya × Penyewa Dikeluarkan secara otomatis
Token pengguna ~7 KB Sumber Daya × Penyewa × Pengguna Pengosongan manual diperlukan
Token penyegaran Variabel Pengguna Berumur panjang

Perencanaan memori

Untuk 500 pengguna bersamaan yang memanggil 3 API:

  • Token pengguna: 500 × 3 × 7 KB = 10,5 MB
  • Dengan overhead: ~15-20 MB

Untuk 10.000 pengguna bersamaan:

  • Token pengguna: 10.000 × 3 × 7 KB = 210 MB
  • Dengan overhead: ~300-350 MB

Rekomendasi: Atur batas ukuran cache L1 berdasarkan pengguna bersamaan yang diharapkan.

Praktik terbaik

Ikuti panduan ini untuk memastikan penyimpanan sementara token yang andal dan efisien.

Menggunakan cache terdistribusi dalam produksi - Penting untuk penyebaran multi-server

Mengatur batas ukuran cache yang sesuai - Mencegah pertumbuhan memori yang tidak terbatas

Mengonfigurasi kebijakan pengusiran - Menyeimbangkan UX dan penggunaan memori

Mengaktifkan enkripsi untuk data sensitif - Melindungi token saat tidak aktif

Memantau kesehatan cache - Melacak tingkat hit, kegagalan, dan performa

Menangani kegagalan cache L2 dengan anggun - Cache L1 memastikan ketahanan

Menguji perilaku cache - Memverifikasi skenario hidupkan ulang dan failover

Jangan gunakan cache memori terdistribusi dalam produksi - Tidak persisten atau terdistribusi

Jangan gunakan cache sesi - Memiliki batasan yang signifikan

Jangan atur kedaluwarsa lebih pendek dari masa pakai token - Memaksa autentikasi ulang yang tidak perlu

Jangan lupa berbagi kunci enkripsi - Sistem terdistribusi memerlukan kunci bersama