Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Panduan ini menunjukkan kepada Anda cara menggunakan cache token Microsoft.Identity.Web dan paket sertifikat dengan MSAL.NET dalam .NET Framework, .NET Standard 2.0, dan aplikasi .NET klasik (.NET 4.7.2+).
Memahami gambaran umum
Dimulai dengan Microsoft. Identity.Web 1.17+, Anda dapat menggunakan Microsoft. Paket utilitas Identity.Web dengan MSAL.NET di lingkungan yang tidak ASP.NET Core.
Mengidentifikasi manfaat paket
| Feature | Keuntungan |
|---|---|
| Serialisasi Cache Token | Adaptor cache yang dapat digunakan kembali untuk memori internal, SQL Server, Redis, Cosmos DB, PostgreSQL |
| Pembantu Sertifikat | Pemuatan sertifikat yang disederhanakan dari KeyVault, sistem file, atau penyimpanan sertifikasi |
| Ekstensi Klaim | Metode utilitas untuk manipulasi ClaimsPrincipal |
| .NET Standar 2.0 | Kompatibel dengan .NET Framework 4.7.2+, .NET Core, dan .NET 5+ |
| Dependensi Minimal | Paket yang ditargetkan tanpa dependensi ASP.NET Core |
Meninjau skenario yang didukung
Skenario berikut didukung dengan paket utilitas yang ditargetkan.
- .NET Framework Console Applications (skenario daemon)
- Aplikasi Desktop (.NET Framework)
- Worker Services (.NET Framework)
- .NET Pustaka Standar 2.0 (kompatibilitas lintas platform)
- Aplikasi MSAL.NET Non-web
Nota
Untuk aplikasi ASP.NET MVC/Web API, lihat integrasi OWIN sebagai gantinya.
Pilih paket
Pilih paket yang cocok dengan skenario Anda.
Mengidentifikasi paket inti untuk MSAL.NET
| Package | Kegunaan | Ketergantungan | Target .NET |
|---|---|---|---|
| Microsoft. Identity.Web.TokenCache | Serializer cache token, ClaimsPrincipal ekstensi |
Minimal | .NET Standar 2.0 |
| Microsoft. Identity.Web.Certificate | Utilitas pemuatan sertifikat | Minimal | .NET Standar 2.0 |
Memasang paket
Gunakan salah satu metode berikut untuk menambahkan paket ke proyek Anda.
Package Manager Console:
# Token cache serialization
Install-Package Microsoft.Identity.Web.TokenCache
# Certificate management
Install-Package Microsoft.Identity.Web.Certificate
.NET CLI:
dotnet add package Microsoft.Identity.Web.TokenCache
dotnet add package Microsoft.Identity.Web.Certificate
Memahami batasan paket inti
Paket core Microsoft.Identity.Web mencakup dependensi ASP.NET Core (Microsoft.AspNetCore.*), yang:
- Tidak kompatibel dengan ASP.NET Framework
- Meningkatkan ukuran paket yang tidak perlu
- Membuat konflik dependensi
Gunakan paket yang ditargetkan sebagai gantinya untuk skenario .NET Framework dan .NET Standard.
Pengaturan serialisasi cache token
Memahami adaptor cache token
Microsoft. Identity.Web menyediakan adaptor cache token yang bekerja tanpa hambatan dengan MSAL.NET IConfidentialClientApplication.
Membangun klien rahasia dengan cache token
Contoh berikut membuat aplikasi klien rahasia dan melampirkan cache token dalam memori.
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders;
public class MsalAppBuilder
{
private static IConfidentialClientApplication _app;
public static IConfidentialClientApplication BuildConfidentialClientApplication()
{
if (_app == null)
{
string clientId = ConfigurationManager.AppSettings["AzureAd:ClientId"];
string clientSecret = ConfigurationManager.AppSettings["AzureAd:ClientSecret"];
string tenantId = ConfigurationManager.AppSettings["AzureAd:TenantId"];
// Create the confidential client application
_app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
.Build();
// Add token cache serialization (choose one option below)
_app.AddInMemoryTokenCache();
}
return _app;
}
}
Pilih opsi cache token
Pilih penyedia cache yang paling sesuai dengan skenario penyebaran Anda.
Mengonfigurasi cache token dalam memori
Contoh berikut menambahkan cache dalam memori sederhana:
using Microsoft.Identity.Web.TokenCacheProviders;
_app.AddInMemoryTokenCache();
Cache dalam memori dengan batas ukuran (Microsoft.Identity.Web 1.20+):
using Microsoft.Extensions.Caching.Memory;
_app.AddInMemoryTokenCache(services =>
{
// Configure memory cache options
services.Configure<MemoryCacheOptions>(options =>
{
options.SizeLimit = 5000000; // 5 MB limit
});
});
Karakteristik:
- Akses cepat
- Tidak ada dependensi eksternal
- Tidak dibagikan antar proses
- Hilang saat menghidupkan ulang aplikasi
Kasus penggunaan: Aplikasi konsol instans tunggal, aplikasi desktop
Mengonfigurasi cache token dalam memori terdistribusi
Gunakan kode berikut untuk menambahkan cache dalam memori terdistribusi untuk lingkungan multi-instans:
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Memory (NuGet)
services.AddDistributedMemoryCache();
});
Karakteristik:
- Dibagikan di seluruh instans aplikasi
- Lebih baik untuk skenario seimbang beban
- Memerlukan paket NuGet tambahan
- Masih hilang saat menghidupkan ulang aplikasi
Kasus penggunaan: Layanan multi-instans dengan akuisisi ulang token yang dapat diterima
Mengonfigurasi cache token SQL Server
Gunakan kode berikut untuk menambahkan cache SQL Server yang persisten dan terdistribusi:
using Microsoft.Extensions.Caching.SqlServer;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.SqlServer (NuGet)
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = ConfigurationManager.ConnectionStrings["TokenCache"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
// IMPORTANT: Set expiration above token lifetime
// Access tokens typically expire after 1 hour
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
Jalankan SQL berikut untuk membuat tabel cache yang diperlukan:
-- Create the cache table
CREATE TABLE [dbo].[TokenCache] (
[Id] NVARCHAR(449) NOT NULL,
[Value] VARBINARY(MAX) NOT NULL,
[ExpiresAtTime] DATETIMEOFFSET NOT NULL,
[SlidingExpirationInSeconds] BIGINT NULL,
[AbsoluteExpiration] DATETIMEOFFSET NULL,
PRIMARY KEY ([Id])
);
-- Create index for performance
CREATE INDEX [Index_ExpiresAtTime] ON [dbo].[TokenCache] ([ExpiresAtTime]);
Karakteristik:
- Persistent setelah dimulai ulang
- Dibagikan di beberapa instans
- Dapat diandalkan dan dapat diskalakan
- Memerlukan penyiapan SQL Server
Kasus penggunaan: Layanan daemon produksi, tugas terjadwal, pekerja multi-instans
Mengonfigurasi cache token Redis
Gunakan kode berikut untuk menambahkan cache terdistribusi Redis berkinerja tinggi:
using StackExchange.Redis;
using Microsoft.Extensions.Caching.StackExchangeRedis;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.StackExchangeRedis (NuGet)
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = ConfigurationManager.AppSettings["Redis:ConnectionString"];
options.InstanceName = "TokenCache_";
});
});
Contoh berikut menunjukkan konfigurasi Redis siap produksi:
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = ConfigurationManager.AppSettings["Redis:ConnectionString"];
options.InstanceName = "MyDaemonApp_";
// Optional: Configure Redis options
options.ConfigurationOptions = new ConfigurationOptions
{
AbortOnConnectFail = false,
ConnectTimeout = 5000,
SyncTimeout = 5000
};
});
Karakteristik:
- Sangat cepat
- Dibagikan di seluruh instance
- Persisten (dengan persistensi Redis diaktifkan)
- Memerlukan server Redis
Kasus penggunaan: Aplikasi daemon volume tinggi, sistem terdistribusi, layanan mikro
Mengonfigurasi cache token Cosmos DB
Gunakan kode berikut untuk menambahkan cache Cosmos DB yang didistribusikan secara global:
using Microsoft.Extensions.Caching.Cosmos;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Cosmos (preview)
services.AddCosmosCache(options =>
{
options.ContainerName = "TokenCache";
options.DatabaseName = "IdentityCache";
options.ClientBuilder = new CosmosClientBuilder(
ConfigurationManager.AppSettings["CosmosConnectionString"]);
options.CreateIfNotExists = true;
});
});
Karakteristik:
- Didistribusikan secara global
- Sangat tersedia
- Penskalaan otomatis
- Latensi yang lebih tinggi daripada Redis
- Biaya lebih tinggi
Kasus penggunaan: Layanan daemon global, aplikasi terdistribusi secara geografis
Mengonfigurasi cache token PostgreSQL
Gunakan kode berikut untuk menambahkan cache PostgreSQL terdistribusi:
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Postgres (NuGet)
services.AddDistributedPostgresCache(options =>
{
options.ConnectionString = ConfigurationManager.ConnectionStrings["PostgresCache"].ConnectionString;
options.SchemaName = ConfigurationManager.AppSettings["PostgresCache:SchemaName"];
options.TableName = ConfigurationManager.AppSettings["PostgresCache:TableName"];
options.CreateIfNotExists = bool.Parse(
ConfigurationManager.AppSettings["PostgresCache:CreateIfNotExists"] ?? "true");
// Set expiration above token lifetime.
// Access tokens typically expire after 1 hour.
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
Karakteristik:
- Persistent setelah dimulai ulang
- Dibagikan di beberapa instans
- Semantik SQL yang akrab
- Bekerja dengan Azure Database for PostgreSQL
- Memerlukan server PostgreSQL
Use case: aplikasi yang sudah menggunakan PostgreSQL sebagai basis data utama, atau layanan yang dihosting Azure menggunakan Azure Database for PostgreSQL
Membangun aplikasi daemon lengkap
Contoh berikut menunjukkan aplikasi daemon lengkap yang memperoleh token menggunakan kredensial klien dan cache token SQL Server.
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders;
using System;
using System.Threading.Tasks;
namespace DaemonApp
{
class Program
{
private static IConfidentialClientApplication _app;
static async Task Main(string[] args)
{
// Build confidential client with token cache
_app = BuildConfidentialClient();
// Acquire token for app-only access
string[] scopes = new[] { "https://graph.microsoft.com/.default" };
try
{
var result = await _app.AcquireTokenForClient(scopes)
.ExecuteAsync();
Console.WriteLine($"Token acquired successfully!");
Console.WriteLine($"Token source: {result.AuthenticationResultMetadata.TokenSource}");
Console.WriteLine($"Expires on: {result.ExpiresOn}");
// Use token to call API
await CallProtectedApi(result.AccessToken);
}
catch (MsalServiceException ex)
{
Console.WriteLine($"Error acquiring token: {ex.ErrorCode}");
Console.WriteLine($"CorrelationId: {ex.CorrelationId}");
}
}
private static IConfidentialClientApplication BuildConfidentialClient()
{
var app = ConfidentialClientApplicationBuilder
.Create(ConfigurationManager.AppSettings["ClientId"])
.WithClientSecret(ConfigurationManager.AppSettings["ClientSecret"])
.WithTenantId(ConfigurationManager.AppSettings["TenantId"])
.Build();
// Add SQL Server token cache for persistence
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = ConfigurationManager
.ConnectionStrings["TokenCache"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
return app;
}
private static async Task CallProtectedApi(string accessToken)
{
// Your API call logic
}
}
}
Mengelola sertifikat
Memahami pemuatan sertifikat
Microsoft. Identity.Web menyederhanakan pemuatan sertifikat dari berbagai sumber untuk alur kredensial klien.
Memuat sertifikat dengan DefaultCertificateLoader
Contoh berikut menunjukkan cara memuat sertifikat dari Azure Key Vault dan membuat aplikasi klien rahasia.
using Microsoft.Identity.Web;
using Microsoft.Identity.Client;
public class CertificateHelper
{
public static IConfidentialClientApplication CreateAppWithCertificate()
{
string clientId = ConfigurationManager.AppSettings["AzureAd:ClientId"];
string tenantId = ConfigurationManager.AppSettings["AzureAd:TenantId"];
// Define certificate source
var certDescription = CertificateDescription.FromKeyVault(
keyVaultUrl: "https://my-keyvault.vault.azure.net",
keyVaultCertificateName: "MyCertificate"
);
// Load certificate
ICertificateLoader certificateLoader = new DefaultCertificateLoader();
certificateLoader.LoadIfNeeded(certDescription);
// Create confidential client with certificate
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
// Add token cache
app.AddInMemoryTokenCache();
return app;
}
}
Pilih sumber sertifikat
Memuat dari Azure Key Vault
Muat sertifikat yang disimpan di Azure Key Vault dengan menentukan URL vault dan nama sertifikat.
var certDescription = CertificateDescription.FromKeyVault(
keyVaultUrl: "https://my-keyvault.vault.azure.net",
keyVaultCertificateName: "MyApplicationCert"
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
Prasyarat:
- Identitas Terkelola atau Perwakilan Layanan dengan akses Key Vault
- paket NuGet
Azure.Identity - izin Key Vault:
Getpada sertifikat
Memuat dari penyimpanan sertifikat
Muat sertifikat dari penyimpanan sertifikat Windows dengan nama khusus.
var certDescription = CertificateDescription.FromStoreWithDistinguishedName(
distinguishedName: "CN=MyApp.contoso.com",
storeName: StoreName.My,
storeLocation: StoreLocation.CurrentUser
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
Anda juga dapat menemukan sertifikat dengan sidik jempol:
var certDescription = CertificateDescription.FromStoreWithThumbprint(
thumbprint: "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
storeName: StoreName.My,
storeLocation: StoreLocation.LocalMachine
);
Memuat dari sistem file
Muat sertifikat dari file PFX pada sistem file lokal.
var certDescription = CertificateDescription.FromPath(
path: @"C:\Certificates\MyAppCert.pfx",
password: ConfigurationManager.AppSettings["Certificate:Password"]
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
Catatan keamanan: Jangan pernah kata sandi hardcode. Gunakan konfigurasi aman.
Memuat dari string yang dikodekan Base64
Muat sertifikat dari string yang dikodekan Base64 yang disimpan dalam konfigurasi.
string base64Cert = ConfigurationManager.AppSettings["Certificate:Base64"];
var certDescription = CertificateDescription.FromBase64Encoded(
base64EncodedValue: base64Cert,
password: ConfigurationManager.AppSettings["Certificate:Password"] // Optional
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
Mengonfigurasi pemuatan sertifikat dari App.config
Tentukan pengaturan sertifikat dalam file App.config Anda dan muat pada runtime.
App.config:
<appSettings>
<add key="AzureAd:ClientId" value="your-client-id" />
<add key="AzureAd:TenantId" value="your-tenant-id" />
<!-- Option 1: KeyVault -->
<add key="Certificate:SourceType" value="KeyVault" />
<add key="Certificate:KeyVaultUrl" value="https://my-vault.vault.azure.net" />
<add key="Certificate:KeyVaultCertificateName" value="MyCert" />
<!-- Option 2: Store -->
<!--
<add key="Certificate:SourceType" value="StoreWithThumbprint" />
<add key="Certificate:CertificateThumbprint" value="ABCD..." />
<add key="Certificate:CertificateStorePath" value="CurrentUser/My" />
-->
</appSettings>
<connectionStrings>
<add name="TokenCache"
connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=TokenCache;Integrated Security=True;" />
</connectionStrings>
Gunakan metode pembantu berikut untuk memuat sertifikat berdasarkan konfigurasi:
public static CertificateDescription GetCertificateFromConfig()
{
string sourceType = ConfigurationManager.AppSettings["Certificate:SourceType"];
return sourceType switch
{
"KeyVault" => CertificateDescription.FromKeyVault(
ConfigurationManager.AppSettings["Certificate:KeyVaultUrl"],
ConfigurationManager.AppSettings["Certificate:KeyVaultCertificateName"]
),
"StoreWithThumbprint" => CertificateDescription.FromStoreWithThumbprint(
ConfigurationManager.AppSettings["Certificate:CertificateThumbprint"],
StoreName.My,
StoreLocation.CurrentUser
),
_ => throw new ConfigurationErrorsException("Invalid certificate source type")
};
}
Menjelajahi aplikasi sampel
Tinjau sampel ini untuk melihat implementasi yang berfungsi.
Tinjau sampel resmi Microsoft
Tabel berikut mencantumkan sampel resmi yang menunjukkan penyimpanan sementara token dan pemrosesan sertifikat.
| Sampel | Platform | Deskripsi |
|---|---|---|
| ConfidentialClientTokenCache | Konsol (kerangka kerja .NET) | Pola serialisasi cache token |
| active-directory-dotnetcore-daemon-v2 | Konsol (.NET Core) | Pemuatan sertifikat dari Key Vault |
Ikuti praktik terbaik
Terapkan pola-pola ini untuk membangun aplikasi yang andal dan aman.
Ikuti pola yang direkomendasikan
1. Gunakan pola singleton untuk IConfidentialClientApplication:
Buat satu instans dan gunakan kembali di seluruh aplikasi Anda.
private static IConfidentialClientApplication _app;
public static IConfidentialClientApplication GetApp()
{
if (_app == null)
{
_app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.Build();
_app.AddDistributedTokenCaches(/* ... */);
}
return _app;
}
2. Atur kedaluwarsa cache token yang sesuai:
Konfigurasikan kedaluwarsa geser di atas masa pakai token untuk mencegah akuisisi ulang yang tidak perlu.
// Access tokens typically expire after 1 hour
// Set cache expiration ABOVE token lifetime
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
3. Gunakan penyimpanan sertifikat aman:
Simpan sertifikat di Azure Key Vault atau penyimpanan sertifikat yang diamankan dengan benar.
// Azure Key Vault (production)
var cert = CertificateDescription.FromKeyVault(keyVaultUrl, certName);
// Certificate store with proper permissions
var cert = CertificateDescription.FromStoreWithThumbprint(
thumbprint, StoreName.My, StoreLocation.LocalMachine);
4. Terapkan penanganan kesalahan yang tepat:
Tangkap pengecualian MSAL dan catat ID korelasi untuk pemecahan masalah.
try
{
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
catch (MsalServiceException ex)
{
logger.Error($"Token acquisition failed. CorrelationId: {ex.CorrelationId}, ErrorCode: {ex.ErrorCode}");
throw;
}
5. Gunakan cache terdistribusi untuk produksi:
Cache terdistribusi berbagi token di antara instans dan tetap bertahan setelah restart.
// Correct for daemon services
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
Hindari kesalahan umum
1. Jangan membuat instans IConfidentialClientApplication baru berulang kali:
// Wrong - creates new instance every time
public void AcquireToken()
{
var app = ConfidentialClientApplicationBuilder.Create(clientId).Build();
// ...
}
// Correct - use singleton
private static readonly IConfidentialClientApplication _app = BuildApp();
2. Jangan hardcode rahasia:
// Wrong
.WithClientSecret("supersecretvalue123")
// Correct
.WithClientSecret(ConfigurationManager.AppSettings["AzureAd:ClientSecret"])
3. Jangan gunakan cache dalam memori untuk layanan multi-instans:
// Wrong for services with multiple instances
app.AddInMemoryTokenCache();
// Correct - use distributed cache
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
4. Jangan abaikan validasi sertifikat:
// Wrong - skips validation
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
// Correct - validate certificates properly
Bermigrasi dari ADAL.NET
Tinjau perbedaan utama dan perbarui kode Anda untuk menggunakan MSAL.NET dengan Microsoft. Identity.Web.
Memahami perbedaan utama
| Aspek | ADAL.NET (tidak digunakan lagi) | MSAL.NET + Microsoft. Identity.Web |
|---|---|---|
| Cakupan | Berbasis sumber daya (https://graph.microsoft.com) |
Berbasis cakupan (https://graph.microsoft.com/.default) |
| Token Cache | Diperlukan serialisasi manual | Adaptor bawaan melalui metode ekstensi |
| Sertifikat | Pemuatan Manual X509Certificate2 |
DefaultCertificateLoader dengan beberapa sumber |
| Wewenang | Diperbaiki saat konstruksi | Dapat ditimpa sesuai permintaan |
Membandingkan contoh migrasi
ADAL.NET (Lama):
AuthenticationContext authContext = new AuthenticationContext(authority);
ClientCredential credential = new ClientCredential(clientId, clientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, credential);
MSAL.NET dengan Microsoft. Identity.Web (Baru):
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.Build();
app.AddInMemoryTokenCache(); // Add token cache
string[] scopes = new[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
Menjelajahi konten terkait
Gunakan sumber daya ini untuk mempelajari selengkapnya tentang skenario terkait.