Paket NuGet Microsoft.Identity.Web.TokenCache menyediakan serialisasi cache token dalam pustaka Microsoft.Identity.Web.
| Metode ekstensi |
Deskripsi |
| AddInMemoryTokenCaches |
Membuat cache sementara di memori untuk penyimpanan dan pengambilan token. Cache token dalam memori lebih cepat daripada jenis cache lainnya, tetapi tokennya tidak bertahan di antara penghidupan ulang aplikasi, dan Anda tidak dapat mengontrol ukuran cache. Cache dalam memori bagus untuk aplikasi yang tidak memerlukan token untuk tetap ada di antara penghidupan ulang aplikasi. Gunakan cache token dalam memori di aplikasi yang berpartisipasi dalam skenario autentikasi mesin-ke-mesin seperti layanan, daemon, dan lainnya yang menggunakan AcquireTokenForClient (pemberian izin informasi masuk klien). Cache token dalam memori juga baik untuk aplikasi sampel dan selama pengembangan aplikasi lokal. Microsoft.Identity.Web versi 1.19.0+ berbagi cache token dalam memori di semua instans aplikasi. |
AddSessionTokenCaches |
Cache token terikat ke sesi pengguna. Opsi ini tidak ideal jika token ID berisi banyak klaim, karena cookie akan menjadi terlalu besar. |
AddDistributedTokenCaches |
Cache token adalah adaptor terhadap penerapan ASP.NET Core IDistributedCache. Hal ini memungkinkan Anda untuk memilih antara cache memori terdistribusi, cache Redis, NCache terdistribusi, atau cache SQL Server. Untuk detail tentang penerapan IDistributedCache, lihat Cache memori terdistribusi. |
Cache token dalam memori
Berikut adalah contoh kode yang menggunakan cache dalam memori dalam metode ConfigureServices kelas Startup dalam aplikasi 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 cocok dalam produksi jika Anda meminta token khusus aplikasi. Jika Anda menggunakan token pengguna, pertimbangkan untuk menggunakan cache token terdistribusi.
Kode konfigurasi cache token antara aplikasi web ASP.NET Core dan API web ini mirip.
Cache token terdistribusi
Berikut adalah contoh kemungkinan cache terdistribusi:
// 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;
});
Untuk informasi selengkapnya, lihat:
Penggunaan cache terdistribusi ditampilkan dalam tutorial aplikasi web ASP.NET Core di cache token fase 2-2.
Bahkan ketika Anda menggunakan MSAL.NET, Anda bisa mendapatkan keuntungan dari pembuat serial cache token di Microsoft.Identity.Web.TokenCache.
Mereferensi paket NuGet
Tambahkan paket NuGet Microsoft.Identity.Web.TokenCache ke proyek Anda, bukan MSAL.NET.
Mengonfigurasi cache token
Kode berikut menunjukkan cara menambahkan cache token yang dipartisi dengan baik dalam memori ke aplikasi Anda.
using Microsoft.Identity.Web;
using Microsoft.Identity.Client;
using Microsoft.Extensions.DependencyInjection;
public static async Task<AuthenticationResult> GetTokenAsync(string clientId, X509Certificate cert, string authority, string[] scopes)
{
// Create the confidential client application
app= ConfidentialClientApplicationBuilder.Create(clientId)
// Alternatively to the certificate, you can use .WithClientSecret(clientSecret)
.WithCertificate(cert)
.WithLegacyCacheCompatibility(false)
.WithAuthority(authority)
.Build();
// Add a static in-memory token cache. Other options available: see below
app.AddInMemoryTokenCache(); // Microsoft.Identity.Web.TokenCache 1.17+
// Make the call to get a token for client_credentials flow (app-to-app scenario)
return await app.AcquireTokenForClient(scopes).ExecuteAsync();
// OR Make the call to get a token for OBO (web API scenario)
return await app.AcquireTokenOnBehalfOf(scopes, userAssertion).ExecuteAsync();
// OR Make the call to get a token via auth code (web app scenario)
return await app.AcquireTokenByAuthorizationCode(scopes, authCode);
// OR, when the user has previously logged in, get a token silently
string homeAccountId = User.GetHomeAccountId(); // uid and utid claims
var account = await app.GetAccountAsync(homeAccountId);
try
{
return await app.AcquireTokenSilent(scopes, account).ExecuteAsync();;
}
catch (MsalUiRequiredException)
{
// cannot get a token silently, so redirect the user to be challenged
}
}
Teknologi caching yang tersedia
Sebagai ganti dari app.AddInMemoryTokenCache();, Anda dapat menggunakan teknologi serialisasi cache yang berbeda. Misalnya, Anda dapat menggunakan penyimpanan cache token tanpa serialisasi, dalam memori, dan terdistribusi yang disediakan oleh .NET.
Cache token tanpa serialisasi
Anda dapat menentukan bahwa Anda tidak ingin memiliki serialisasi cache token dan sebagai gantinya mengandalkan cache internal MSAL.NET:
- Menggunakan
.WithCacheOptions(CacheOptions.EnableSharedCacheOptions) saat membuat aplikasi.
- Tidak menambahkan serializer apa pun.
// Create the confidential client application
app= ConfidentialClientApplicationBuilder.Create(clientId)
// Alternatively to the certificate, you can use .WithClientSecret(clientSecret)
.WithCertificate(cert)
.WithLegacyCacheCompatibility(false)
.WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
.WithAuthority(authority)
.Build();
WithCacheOptions(CacheOptions.EnableSharedCacheOptions) membuat cache token MSAL internal dibagikan di antara instans aplikasi klien MSAL. Berbagi cache token lebih cepat daripada menggunakan serialisasi cache token apa pun, tetapi cache token dalam memori internal tidak memiliki kebijakan pengeluaran. Token yang ada akan direfresh di tempat, tetapi mengambil token untuk pengguna, penyewa, dan sumber daya yang berbeda membuat cache berkembang sesuai dengan hal tersebut.
Jika Anda menggunakan pendekatan ini dan memiliki banyak pengguna atau penyewa, pastikan untuk memantau jejak memori. Jika jejak memori menjadi masalah, pertimbangkan untuk mengaktifkan serialisasi cache token, yang dapat mengurangi ukuran cache internal. Perlu diketahui juga bahwa saat ini, Anda tidak dapat menggunakan cache bersama dan serialisasi cache secara bersamaan.
Cache token dalam memori
Serialisasi cache token dalam memori sangat bagus dalam sampel. Hal ini juga bagus dalam aplikasi produksi jika Anda hanya meminta token aplikasi (AcquireTokenForClient), asalkan Anda tidak keberatan jika cache token hilang saat aplikasi web dihidupkan ulang. Kami tidak merekomendasikannya dalam produksi jika Anda meminta token pengguna (AcquireTokenByAuthorizationCode, AcquireTokenSilent, AcquireTokenOnBehalfOf).
// Add an in-memory token cache
app.AddInMemoryTokenCache();
Anda juga dapat menentukan opsi untuk membatasi ukuran cache token dalam memori:
// Add an in-memory token cache with options
app.AddInMemoryTokenCache(services =>
{
// Configure the memory cache options
services.Configure<MemoryCacheOptions>(options =>
{
options.SizeLimit = 500 * 1024 * 1024; // in bytes (500 MB)
});
}
);
Cache terdistribusi
Jika Anda menggunakan app.AddDistributedTokenCache, cache token adalah adaptor implementasi .NET IDistributedCache. Jadi, Anda dapat memilih antara cache SQL Server, cache Redis cache, cache Azure Cosmos DB, atau cache lain yang menerapkan antarmuka IDistributedCache.
Khusus untuk tujuan pengujian, sebaiknya Anda menggunakan services.AddDistributedMemoryCache(), sebuah implementasi dalam memori IDistributedCache.
Berikut kode untuk cache SQL Server:
// SQL Server token cache
app.AddDistributedTokenCache(services =>
{
services.AddDistributedSqlServerCache(options =>
{
// Requires to reference Microsoft.Extensions.Caching.SqlServer
options.ConnectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=TestCache;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
options.SchemaName = "dbo";
options.TableName = "TestCache";
// You don't want the SQL token cache to be purged before the access token has expired. Usually
// access tokens expire after 1 hour (but this can be changed by token lifetime policies), whereas
// the default sliding expiration for the distributed SQL database is 20 mins.
// Use a value above 60 mins (or the lifetime of a token in case of longer-lived tokens)
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
Berikut kode untuk cache Redis:
// Redis token cache
app.AddDistributedTokenCache(services =>
{
// Requires to reference Microsoft.Extensions.Caching.StackExchangeRedis
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "Redis";
});
// 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;
};
});
});
Berikut kode untuk cache Azure Cosmos DB:
// Azure Cosmos DB token cache
app.AddDistributedTokenCache(services =>
{
// Requires to reference Microsoft.Extensions.Caching.Cosmos
services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
cacheOptions.ClientBuilder = new CosmosClientBuilder(Configuration["CosmosConnectionString"]);
cacheOptions.CreateIfNotExists = true;
});
});
Untuk mengetahui informasi selengkapnya tentang cache terdistribusi, lihat:
Menonaktifkan cache token lama
MSAL memiliki beberapa kode internal khusus untuk memungkinkan interaksi dengan cache Pustaka Autentikasi Microsoft (ADAL) lama. Ketika MSAL dan ADAL tidak digunakan secara berdampingan, cache lama tidak digunakan dan kode lama terkait tidak diperlukan. MSAL 4.25.0 menambahkan kemampuan untuk menonaktifkan kode tembolok ADAL lawas dan meningkatkan kinerja penggunaan cache. Untuk perbandingan performa sebelum dan setelah menonaktifkan cache lama, lihat permintaan pull GitHub 2309.
Panggil .WithLegacyCacheCompatibility(false) pada penyusun aplikasi seperti kode berikut.
var app = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithClientSecret(clientSecret)
.WithLegacyCacheCompatibility(false)
.Build();
Sampel
Di aplikasi desktop, sebaiknya Anda menggunakan cache token lintas platform. MSAL.NET menyediakan cache token lintas platform di pustaka terpisah bernama Microsoft.Identity.Client.Extensions.Msal.
Mereferensi paket NuGet
Tambahkan paket NuGet Microsoft.Identity.Client.Extensions.Msal ke proyek Anda.
Mengonfigurasi cache token
Untuk detailnya, lihat halaman wiki. Berikut adalah contoh penggunaan cache token lintas platform:
var storageProperties =
new StorageCreationPropertiesBuilder(Config.CacheFileName, Config.CacheDir)
.WithLinuxKeyring(
Config.LinuxKeyRingSchema,
Config.LinuxKeyRingCollection,
Config.LinuxKeyRingLabel,
Config.LinuxKeyRingAttr1,
Config.LinuxKeyRingAttr2)
.WithMacKeyChain(
Config.KeyChainServiceName,
Config.KeyChainAccountName)
.Build();
IPublicClientApplication pca = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(Config.Authority)
.WithRedirectUri("http://localhost") // make sure to register this redirect URI for the interactive login
.Build();
// This hooks up the cross-platform cache into MSAL
var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties );
cacheHelper.RegisterCache(pca.UserTokenCache);
Mode fallback teks biasa
Cache token lintas platform memungkinkan Anda menyimpan token yang tidak terenkripsi dalam teks biasa. Fitur ini dimaksudkan untuk digunakan dalam lingkungan pengembangan hanya untuk tujuan penelusuran kesalahan.
Anda dapat menggunakan mode fallback teks biasa dengan menggunakan pola kode berikut.
storageProperties =
new StorageCreationPropertiesBuilder(
Config.CacheFileName + ".plaintext",
Config.CacheDir)
.WithUnprotectedFile()
.Build();
var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false);
MSAL.NET menyediakan cache token dalam memori secara default. Serialisasi disediakan secara default untuk platform di mana penyimpanan aman tersedia untuk pengguna sebagai bagian dari platform: Universal Windows Platform (UWP), Xamarin.iOS, dan Xamarin.Android.
Jika Anda ingin menulis pembuat serialisasi cache token Anda sendiri, MSAL.NET menyediakan serialisasi cache token kustom di subplatform .NET Framework dan .NET Core. Peristiwa diaktifkan ketika cache diakses. Aplikasi dapat memilih apakah akan membuat serialisasi atau membatalkan serialisasi cache.
Pada aplikasi klien rahasia yang menangani pengguna (aplikasi web yang memasukkan pengguna dan memanggil API web, dan API web yang memanggil API web hilir), terdapat banyak pengguna. Pengguna diproses secara paralel. Untuk alasan keamanan dan kinerja, rekomendasi kami adalah menyerialisasikan satu cache per pengguna. Peristiwa serialisasi menghitung kunci cache berdasarkan identitas pengguna yang diproses dan membuat serialisasi atau membatalkan serialisasi cache token untuk pengguna tersebut.
Ingat, serialisasi kustom tidak tersedia di platform seluler (UWP, Xamarin.iOS, dan Xamarin.Android). MSAL sudah mendefinisikan mekanisme serialisasi yang aman dan berkinerja untuk platform ini. Namun, aplikasi .NET desktop dan .NET Core memiliki arsitektur yang bervariasi. Dan MSAL tidak dapat menerapkan mekanisme serialisasi tujuan umum.
Misalnya, situs web mungkin memilih untuk menyimpan token dalam cache Redis, atau aplikasi desktop mungkin menyimpan token dalam file terenkripsi. Jadi serialisasi tidak disediakan di luar kotak. Untuk memiliki aplikasi cache token persisten di desktop .NET atau .NET Core, sesuaikan serialisasi.
Kelas dan antarmuka berikut digunakan dalam serialisasi cache token:
ITokenCache menentukan peristiwa untuk berlangganan permintaan serialisasi cache token dan metode untuk membuat serialisasi atau membatalkan serialisasi cache pada berbagai format (ADAL v3.0, MSAL 2.x, dan MSAL 3.x = ADAL v5.0).
TokenCacheCallback adalah panggilan balik yang diteruskan ke acara sehingga Anda dapat menangani serialisasi. Mereka akan dipanggil dengan argumen tipe TokenCacheNotificationArgs.
TokenCacheNotificationArgs hanya memberikan nilai ClientId aplikasi dan referensi ke pengguna yang tokennya tersedia.

Penting
MSAL.NET membuat cache token untuk Anda. Hal ini memberi Anda cache IToken saat Anda memanggil properti UserTokenCache dan AppTokenCache aplikasi. Anda tidak seharusnya menerapkan antarmuka sendiri.
Tanggung jawab Anda, ketika Anda menerapkan serialisasi cache token kustom, adalah untuk bereaksi terhadap peristiwa BeforeAccess dan AfterAccess (atau varietas Async mereka). Delegasi BeforeAccess bertanggung jawab untuk membatalkan serialisasi cache, sedangkan delegasi AfterAccess bertanggung jawab untuk membuat serial cache. Bagian dari peristiwa ini menyimpan atau memuat blob, yang diteruskan melalui argumen peristiwa ke penyimpanan apa pun yang Anda inginkan.
Strateginya berbeda bergantung pada apakah Anda menulis serialisasi cache token untuk aplikasi klien publik (desktop) atau aplikasi klien rahasia (aplikasi web, API web, aplikasi daemon).
Cache token kustom untuk aplikasi web atau API web (aplikasi klien rahasia)
Jika Anda ingin menulis pembuat serial cache token Anda sendiri untuk aplikasi klien rahasia, sebaiknya Anda mewarisi dari Microsoft.Identity.Web.MsalAbstractTokenCacheProvider dan mengganti metode WriteCacheBytesAsync dan ReadCacheBytesAsync.
Contoh pembuat serial cache token disediakan di Microsoft.Identity.Web/TokenCacheProviders.
Cache token khusus untuk aplikasi desktop atau seluler (aplikasi klien publik)
Di MSAL.NET v2.x, Anda memiliki beberapa opsi untuk membuat serial cache token dari klien publik. Anda hanya dapat membuat serial cache ke format MSAL.NET. (Tembolokan format terpadu umum pada seluruh MSAL dan platform.) Anda juga dapat mendukung serialisasi tembolokan token legacy ADAL v3.
Kustomisasi serialisasi tembolokan token untuk berbagi status SSO antara ADAL.NET 3.x, ADAL.NET 5.x, dan MSAL.NET dijelaskan dalam bagian dari sampel berikut: active-directory-dotnet-v1-to-v2.
Catatan
Format cache token MSAL.NET 1.1.4-preview tidak lagi didukung dalam MSAL 2.x. Jika Anda memiliki aplikasi yang menggunakan MSAL.NET 1.x, pengguna Anda harus masuk kembali. Migrasi dari ADAL 4.x (dan 3.x) didukung.
Serialisasi cache token sederhana (hanya MSAL)
Kode berikut adalah contoh penerapan naif serialisasi kustom cache token untuk aplikasi desktop. Di sini, cache token pengguna adalah file di folder yang sama dengan aplikasi.
Setelah membangun aplikasi, Anda mengaktifkan serialisasi dengan memanggil metode TokenCacheHelper.EnableSerialization() dan meneruskan properti UserTokenCache aplikasi.
app = PublicClientApplicationBuilder.Create(ClientId)
.Build();
TokenCacheHelper.EnableSerialization(app.UserTokenCache);
Kelas pembantu TokenCacheHelper didefinisikan sebagai:
static class TokenCacheHelper
{
public static void EnableSerialization(ITokenCache tokenCache)
{
tokenCache.SetBeforeAccess(BeforeAccessNotification);
tokenCache.SetAfterAccess(AfterAccessNotification);
}
/// <summary>
/// Path to the token cache. Note that this could be something different, for instance, for MSIX applications:
/// private static readonly string CacheFilePath =
/// $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\{AppName}\msalcache.bin";
/// </summary>
public static readonly string CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + ".msalcache.bin3";
private static readonly object FileLock = new object();
private static void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
lock (FileLock)
{
args.TokenCache.DeserializeMsalV3(File.Exists(CacheFilePath)
? ProtectedData.Unprotect(File.ReadAllBytes(CacheFilePath),
null,
DataProtectionScope.CurrentUser)
: null);
}
}
private static void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if the access operation resulted in a cache update
if (args.HasStateChanged)
{
lock (FileLock)
{
// reflect changes in the persistent store
File.WriteAllBytes(CacheFilePath,
ProtectedData.Protect(args.TokenCache.SerializeMsalV3(),
null,
DataProtectionScope.CurrentUser)
);
}
}
}
}
Pembuat serial cache token berbasis file berkualitas produk untuk aplikasi klien publik (untuk aplikasi desktop yang berjalan di Windows, Mac, dan Linux) tersedia dari pustaka sumber terbuka Microsoft.Identity.Client.Extensions.Msal. Anda dapat menyertakannya dalam aplikasi Anda dari paket NuGet berikut: Microsoft.Identity.Client.Extensions.Msal.
Serialisasi cache token ganda (cache terpadu MSAL dan ADAL v3)
Jika Anda ingin menerapkan serialisasi cache token dengan format cache terpadu (umum untuk ADAL.NET 4.x, MSAL.NET 2.x, dan MSAL lain dari generasi yang sama atau yang lebih lama, pada platform yang sama), lihat kode berikut:
string appLocation = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location;
string cacheFolder = Path.GetFullPath(appLocation) + @"..\..\..\..");
string adalV3cacheFileName = Path.Combine(cacheFolder, "cacheAdalV3.bin");
string unifiedCacheFileName = Path.Combine(cacheFolder, "unifiedCache.bin");
IPublicClientApplication app;
app = PublicClientApplicationBuilder.Create(clientId)
.Build();
FilesBasedTokenCacheHelper.EnableSerialization(app.UserTokenCache,
unifiedCacheFileName,
adalV3cacheFileName);
Kali ini, kelas pembantu didefinisikan sebagai:
using System;
using System.IO;
using System.Security.Cryptography;
using Microsoft.Identity.Client;
namespace CommonCacheMsalV3
{
/// <summary>
/// Simple persistent cache implementation of the dual cache serialization (ADAL v3 legacy
/// and unified cache format) for a desktop applications (from MSAL 2.x)
/// </summary>
static class FilesBasedTokenCacheHelper
{
/// <summary>
/// Enables the serialization of the token cache
/// </summary>
/// <param name="adalV3CacheFileName">File name where the cache is serialized with the
/// ADAL v3 token cache format. Can
/// be <c>null</c> if you don't want to implement the legacy ADAL v3 token cache
/// serialization in your MSAL 2.x+ application</param>
/// <param name="unifiedCacheFileName">File name where the cache is serialized
/// with the unified cache format, common to
/// ADAL v4 and MSAL v2 and later, and also across ADAL/MSAL on the same platform.
/// Should not be <c>null</c></param>
/// <returns></returns>
public static void EnableSerialization(ITokenCache tokenCache, string unifiedCacheFileName, string adalV3CacheFileName)
{
UnifiedCacheFileName = unifiedCacheFileName;
AdalV3CacheFileName = adalV3CacheFileName;
tokenCache.SetBeforeAccess(BeforeAccessNotification);
tokenCache.SetAfterAccess(AfterAccessNotification);
}
/// <summary>
/// File path where the token cache is serialized with the unified cache format
/// (ADAL.NET v4, MSAL.NET v3)
/// </summary>
public static string UnifiedCacheFileName { get; private set; }
/// <summary>
/// File path where the token cache is serialized with the legacy ADAL v3 format
/// </summary>
public static string AdalV3CacheFileName { get; private set; }
private static readonly object FileLock = new object();
public static void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
lock (FileLock)
{
args.TokenCache.DeserializeAdalV3(ReadFromFileIfExists(AdalV3CacheFileName));
try
{
args.TokenCache.DeserializeMsalV3(ReadFromFileIfExists(UnifiedCacheFileName));
}
catch(Exception ex)
{
// Compatibility with the MSAL v2 cache if you used one
args.TokenCache.DeserializeMsalV2(ReadFromFileIfExists(UnifiedCacheFileName));
}
}
}
public static void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if the access operation resulted in a cache update
if (args.HasStateChanged)
{
lock (FileLock)
{
WriteToFileIfNotNull(UnifiedCacheFileName, args.TokenCache.SerializeMsalV3());
if (!string.IsNullOrWhiteSpace(AdalV3CacheFileName))
{
WriteToFileIfNotNull(AdalV3CacheFileName, args.TokenCache.SerializeAdalV3());
}
}
}
}
/// <summary>
/// Read the content of a file if it exists
/// </summary>
/// <param name="path">File path</param>
/// <returns>Content of the file (in bytes)</returns>
private static byte[] ReadFromFileIfExists(string path)
{
byte[] protectedBytes = (!string.IsNullOrEmpty(path) && File.Exists(path))
? File.ReadAllBytes(path) : null;
byte[] unprotectedBytes = encrypt ?
((protectedBytes != null) ? ProtectedData.Unprotect(protectedBytes, null, DataProtectionScope.CurrentUser) : null)
: protectedBytes;
return unprotectedBytes;
}
/// <summary>
/// Writes a blob of bytes to a file. If the blob is <c>null</c>, deletes the file
/// </summary>
/// <param name="path">path to the file to write</param>
/// <param name="blob">Blob of bytes to write</param>
private static void WriteToFileIfNotNull(string path, byte[] blob)
{
if (blob != null)
{
byte[] protectedBytes = encrypt
? ProtectedData.Protect(blob, null, DataProtectionScope.CurrentUser)
: blob;
File.WriteAllBytes(path, protectedBytes);
}
else
{
File.Delete(path);
}
}
// Change if you want to test with an unencrypted blob (this is a JSON format)
private static bool encrypt = true;
}
}
Contoh berikut mengilustrasikan serialisasi cache token.