Memigrasikan aplikasi klien rahasia dari ADAL.NET ke MSAL.NET
Artikel
11 menit untuk membaca
Dalam pedoman ini, Anda akan memigrasikan aplikasi klien rahasia dari Pustaka Autentikasi Azure Active Directory untuk .NET (ADAL.NET) ke Pustaka Autentikasi Microsoft untuk .NET (MSAL.NET). Aplikasi klien rahasia mencakup aplikasi web, API web, dan aplikasi daemon yang memanggil layanan lain atas nama mereka sendiri. Untuk informasi selengkapnya tentang aplikasi rahasia, lihat Alur autentikasi dan skenario aplikasi. Jika aplikasi Anda berbasis ASP.NET Core, lihat Microsoft.Identity.Web.
Untuk registrasi aplikasi:
Anda tidak perlu membuat pendaftaran aplikasi baru. (Anda tetap memiliki ID klien yang sama.)
Anda tidak perlu mengubah praotorisasi (izin API yang disetujui admin).
Langkah migrasi
Cari kode yang menggunakan ADAL.NET di aplikasi Anda.
Kode yang menggunakan ADAL dalam aplikasi klien rahasia menginstansiasi AuthenticationContext dan memanggil AcquireTokenByAuthorizationCode atau satu mengambil alih AcquireTokenAsync dengan parameter berikut:
String resourceId. Variabel ini adalah URI ID aplikasi dari API web yang ingin Anda panggil.
Instans dari IClientAssertionCertificate atau ClientAssertion. Instans ini memberikan info masuk klien untuk aplikasi Anda untuk membuktikan identitas aplikasi Anda.
Setelah Anda mengidentifikasi bahwa Anda memiliki aplikasi yang menggunakan ADAL.NET, instal paket NuGet MSAL.NET Microsoft.Identity.Client dan perbarui referensi pustaka proyek Anda. Untuk informasi selengkapnya, lihat Menginstal paket NuGet. Untuk menggunakan pembuat serialisasi cache token, pasang Microsoft.Identity.Web.TokenCache.
Perbarui kode sesuai dengan skenario klien rahasia. Beberapa langkah bersifat umum dan berlaku di semua skenario klien rahasia. Langkah-langkah lain bersifat unik untuk setiap skenario.
Skenario klien rahasia:
Skenario daemon didukung oleh aplikasi web, API web, dan aplikasi konsol daemon.
Anda mungkin telah memberikan wrapper di sekitar ADAL.NET untuk menangani sertifikat dan penembolokan. Pedoman ini menggunakan pendekatan yang sama untuk menggambarkan proses migrasi dari ADAL.NET ke MSAL.NET. Namun, kode ini hanya untuk tujuan demonstrasi. Jangan menyalin/menempelkan wrapper ini atau mengintegrasikannya dalam kode Anda sebagaimana mestinya.
Skenario Daemon menggunakan alur info masuk klien OAuth2.0. Skenario tersebut juga disebut panggilan layanan-ke-layanan. Aplikasi Anda memperoleh token atas namanya sendiri, bukan atas nama pengguna.
Cari tahu apakah kode Anda menggunakan skenario daemon
Kode ADAL untuk aplikasi Anda menggunakan skenario daemon jika berisi panggilan AuthenticationContext.AcquireTokenAsync dengan parameter berikut:
Sumber daya (URI ID aplikasi) sebagai parameter pertama
IClientAssertionCertificate atau ClientAssertion sebagai parameter kedua
AuthenticationContext.AcquireTokenAsync tidak memiliki parameter jenis UserAssertion. Jika memiliki, maka aplikasi Anda adalah API web, dan menggunakan skenario API web yang memanggil API web hilir.
Memperbarui kode skenario daemon
Langkah-langkah berikut untuk memperbarui kode yang berlaku di semua skenario klien rahasia:
Tambah namespace layanan MSAL.NET dalam kode sumber Anda: using Microsoft.Identity.Client;.
Alih-alih membuat instans AuthenticationContext, gunakan ConfidentialClientApplicationBuilder.Create untuk membuat instans IConfidentialClientApplication.
Alih-alih untai (karakter) resourceId, MSAL.NET menggunakan cakupan. Karena aplikasi yang menggunakan ADAL.NET telah diotorisasi sebelumnya, Anda dapat selalu menggunakan cakupan berikut: new string[] { $"{resourceId}/.default" }.
Ganti panggilan AuthenticationContext.AcquireTokenAsync dengan panggilan ke IConfidentialClientApplication.AcquireTokenXXX, di mana XXX bergantung pada skenario Anda.
Dalam kasus ini, ganti panggilan ke AuthenticationContext.AcquireTokenAsync dengan panggilan ke IConfidentialClientApplication.AcquireTokenClient.
Berikut adalah perbandingan kode ADAL.NET dan MSAL.NET untuk skenario daemon:
ADAL
MSAL
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (AppID)";
const string authority
= "https://login.microsoftonline.com/{tenant}";
// App ID URI of web API to call
const string resourceId = "https://target-api.domain.com";
X509Certificate2 certificate = LoadCertificate();
public async Task<AuthenticationResult> GetAuthenticationResult()
{
var authContext = new AuthenticationContext(authority);
var clientAssertionCert = new ClientAssertionCertificate(
ClientId,
certificate);
var authResult = await authContext.AcquireTokenAsync(
resourceId,
clientAssertionCert,
);
return authResult;
}
}
using Microsoft.Identity.Client;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (Application ID)";
const string authority
= "https://login.microsoftonline.com/{tenant}";
// App ID URI of web API to call
const string resourceId = "https://target-api.domain.com";
X509Certificate2 certificate = LoadCertificate();
IConfidentialClientApplication app;
public async Task<AuthenticationResult> GetAuthenticationResult()
{
if (app == null)
{
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.Build();
}
var authResult = await app.AcquireTokenForClient(
new [] { $"{resourceId}/.default" })
// .WithTenantId(specificTenant)
// See https://aka.ms/msal.net/withTenantId
.ExecuteAsync()
.ConfigureAwait(false);
return authResult;
}
}
Dapatkan manfaat dari penembolokan token
Untuk mendapatkan keuntungan dari cache dalam memori, instans IConfidentialClientApplication perlu disimpan dalam variabel anggota. Jika Anda membuat ulang aplikasi klien rahasia setiap kali Anda meminta token, Anda tidak akan mendapat manfaat dari cache token.
API Web yang memanggil API web hilir menggunakan alur OAuth2.0 atas nama (OBO). API web menggunakan token akses yang diambil dari header Otorisasi HTTP dan memvalidasi token ini. Token ini kemudian ditukar dengan token yang lain untuk memanggil API web downstream. Token ini digunakan sebagai instans UserAssertion di ADAL.NET dan MSAL.NET.
Cari tahu apakah kode Anda menggunakan OBO
Kode ADAL untuk aplikasi Anda menggunakan OBO jika berisi panggilan AuthenticationContext.AcquireTokenAsync dengan parameter berikut:
Sumber daya (URI ID aplikasi) sebagai parameter pertama
IClientAssertionCertificate atau ClientAssertion sebagai parameter kedua
Parameter jenis UserAssertion
Memperbarui kode dengan menggunakan OBO
Langkah-langkah berikut untuk memperbarui kode yang berlaku di semua skenario klien rahasia:
Tambah namespace layanan MSAL.NET dalam kode sumber Anda: using Microsoft.Identity.Client;.
Alih-alih membuat instans AuthenticationContext, gunakan ConfidentialClientApplicationBuilder.Create untuk membuat instans IConfidentialClientApplication.
Alih-alih untai (karakter) resourceId, MSAL.NET menggunakan cakupan. Karena aplikasi yang menggunakan ADAL.NET telah diotorisasi sebelumnya, Anda dapat selalu menggunakan cakupan berikut: new string[] { $"{resourceId}/.default" }.
Ganti panggilan AuthenticationContext.AcquireTokenAsync dengan panggilan ke IConfidentialClientApplication.AcquireTokenXXX, di mana XXX bergantung pada skenario Anda.
Dalam kasus ini, kami menggantikan panggilan ke AuthenticationContext.AcquireTokenAsync dengan panggilan ke IConfidentialClientApplication.AcquireTokenOnBehalfOf.
Berikut perbandingan sampel kode OBO untuk ADAL.NET dan MSAL.NET:
ADAL
MSAL
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (AppID)";
const string authority
= "https://login.microsoftonline.com/common";
X509Certificate2 certificate = LoadCertificate();
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId,
string tokenUsedToCallTheWebApi)
{
var authContext = new AuthenticationContext(authority);
var clientAssertionCert = new ClientAssertionCertificate(
ClientId,
certificate);
var userAssertion = new UserAssertion(tokenUsedToCallTheWebApi);
var authResult = await authContext.AcquireTokenAsync(
resourceId,
clientAssertionCert,
userAssertion,
);
return authResult;
}
}
using Microsoft.Identity.Client;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (Application ID)";
const string authority
= "https://login.microsoftonline.com/common";
X509Certificate2 certificate = LoadCertificate();
IConfidentialClientApplication app;
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId,
string tokenUsedToCallTheWebApi)
{
if (app == null)
{
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.Build();
}
var userAssertion = new UserAssertion(tokenUsedToCallTheWebApi);
var authResult = await app.AcquireTokenOnBehalfOf(
new string[] { $"{resourceId}/.default" },
userAssertion)
// .WithTenantId(specificTenant)
// See https://aka.ms/msal.net/withTenantId
.ExecuteAsync()
.ConfigureAwait(false);
return authResult;
}
}
Aplikasi web yang masuk ke pengguna dan memanggil API web atas nama pengguna menggunakan alur kode otorisasi OAuth2.0. Biasanya:
Aplikasi memasukkan pengguna dengan menjalankan bagian pertama alur kode otorisasi dengan masuk ke titik akhir otorisasi platform identitas Microsoft. Pengguna masuk dan melakukan autentikasi multifaktor jika diperlukan. Sebagai hasil dari operasi ini, aplikasi menerima kode otorisasi. Pustaka autentikasi tidak digunakan pada tahap ini.
Aplikasi ini menjalankan bagian kedua dari alur kode otorisasi. Hal itu menggunakan kode otorisasi untuk mendapatkan token akses, token ID, dan token refresh. Aplikasi Anda perlu memberikan nilai redirectUri, yang merupakan URI tempat titik akhir platform identitas Microsoft menyediakan token keamanan. Setelah aplikasi menerima URI itu, biasanya AcquireTokenByAuthorizationCode meminta ADAL atau MSAL untuk menebus kode dan untuk mendapatkan token yang akan disimpan dalam cache token.
Aplikasi ini menggunakan ADAL atau MSAL untuk memanggil AcquireTokenSilent sehingga bisa mendapatkan token untuk memanggil API web yang diperlukan dari pengontrol aplikasi web.
Cari tahu apakah kode Anda menggunakan alur kode auth
Kode ADAL untuk aplikasi Anda menggunakan alur kode auth jika berisi panggilan ke AuthenticationContext.AcquireTokenByAuthorizationCodeAsync.
Memperbarui kode dengan menggunakan alur kode otorisasi
Langkah-langkah berikut untuk memperbarui kode yang berlaku di semua skenario klien rahasia:
Tambah namespace layanan MSAL.NET dalam kode sumber Anda: using Microsoft.Identity.Client;.
Alih-alih membuat instans AuthenticationContext, gunakan ConfidentialClientApplicationBuilder.Create untuk membuat instans IConfidentialClientApplication.
Alih-alih untai (karakter) resourceId, MSAL.NET menggunakan cakupan. Karena aplikasi yang menggunakan ADAL.NET telah diotorisasi sebelumnya, Anda dapat selalu menggunakan cakupan berikut: new string[] { $"{resourceId}/.default" }.
Ganti panggilan AuthenticationContext.AcquireTokenAsync dengan panggilan ke IConfidentialClientApplication.AcquireTokenXXX, di mana XXX bergantung pada skenario Anda.
Dalam kasus ini, ganti panggilan ke AuthenticationContext.AcquireTokenAsync dengan panggilan ke IConfidentialClientApplication.AcquireTokenByAuthorizationCode.
Berikut perbandingan alur kode otorisasi sampel untuk ADAL.NET dan MSAL.NET:
ADAL
MSAL
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (AppID)";
const string authority
= "https://login.microsoftonline.com/common";
private Uri redirectUri = new Uri("host/login_oidc");
X509Certificate2 certificate = LoadCertificate();
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId,
string authorizationCode)
{
var ac = new AuthenticationContext(authority);
var clientAssertionCert = new ClientAssertionCertificate(
ClientId,
certificate);
var authResult = await ac.AcquireTokenByAuthorizationCodeAsync(
authorizationCode,
redirectUri,
clientAssertionCert,
resourceId,
);
return authResult;
}
}
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using System;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (Application ID)";
const string authority
= "https://login.microsoftonline.com/{tenant}";
private Uri redirectUri = new Uri("host/login_oidc");
X509Certificate2 certificate = LoadCertificate();
public IConfidentialClientApplication CreateApplication()
{
IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.WithRedirectUri(redirectUri.ToString())
.WithLegacyCacheCompatibility(false)
.Build();
// Add a token cache. For details about other serialization
// see https://aka.ms/msal-net-cca-token-cache-serialization
app.AddInMemoryTokenCache();
return app;
}
// Called from 'code received event'.
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId,
string authorizationCode)
{
IConfidentialClientApplication app = CreateApplication();
var authResult = await app.AcquireTokenByAuthorizationCode(
new[] { $"{resourceId}/.default" },
authorizationCode)
.ExecuteAsync()
.ConfigureAwait(false);
return authResult;
}
}
Panggilan AcquireTokenByAuthorizationCode menambahkan token ke cache token saat kode otorisasi diterima. Untuk mendapatkan token tambahan untuk sumber daya atau penyewa lain, gunakan AcquireTokenSilent di pengontrol Anda.
public partial class AuthWrapper
{
// Called from controllers
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId2,
string authority)
{
IConfidentialClientApplication app = CreateApplication();
AuthenticationResult authResult;
var scopes = new[] { $"{resourceId2}/.default" };
var account = await app.GetAccountAsync(ClaimsPrincipal.Current.GetMsalAccountId());
try
{
// try to get an already cached token
authResult = await app.AcquireTokenSilent(
scopes,
account)
// .WithTenantId(specificTenantId)
// See https://aka.ms/msal.net/withTenantId
.ExecuteAsync().ConfigureAwait(false);
}
catch (MsalUiRequiredException)
{
// The controller will need to challenge the user
// including asking for claims={ex.Claims}
throw;
}
return authResult;
}
}
Dapatkan manfaat dari penembolokan token
Karena aplikasi web Anda menggunakan AcquireTokenByAuthorizationCode, aplikasi Anda perlu menggunakan cache token terdistribusi untuk penembolokan token. Untuk detailnya, lihat Cache token untuk aplikasi web atau API web dan baca kode sampel.
app.UseInMemoryTokenCaches(); // or a distributed token cache.
Menangani MsalUiRequiredException
Ketika pengontrol Anda mencoba memperoleh token secara diam-diam untuk cakupan/sumber daya yang berbeda, MSAL.NET mungkin melempar MsalUiRequiredException seperti yang diharapkan jika pengguna perlu masuk kembali, atau jika akses ke sumber daya memerlukan lebih banyak klaim (karena kebijakan akses bersyarat). Untuk detail tentang mitigasi, lihat cara Menangani kesalahan dan pengecualian di MSAL.NET.
Manfaat utama dari MSAL.NET untuk aplikasi Anda meliputi:
Ketahanan. MSAL.NET membantu membuat aplikasi Anda tangguh melalui:
Manfaat Azure AD Cached Credential Service (CCS). CCS beroperasi sebagai cadangan Azure AD.
Pembaruan token secara proaktif jika API yang Anda hubungi memungkinkan token berumur panjang melalui evaluasi akses berkelanjutan.
Keamanan. Anda dapat memperoleh token Proof of Possession (PoP) jika API web yang ingin Anda hubungi membutuhkannya. Untuk detailnya, lihat token PoP di MSAL.NET
Performa dan skalabilitas. Jika Anda tidak perlu berbagi cache Anda dengan ADAL.NET, nonaktifkan kompatibilitas cache lama saat Anda membuat aplikasi klien rahasia (.WithLegacyCacheCompatibility(false)) untuk meningkatkan performa secara signifikan.
Informasi pemecahan masalah berikut membuat dua asumsi:
Kode ADAL.NET Anda berfungsi.
Anda bermigrasi ke MSAL dengan menyimpan ID klien yang sama.
Jika Anda mendapatkan pengecualian dengan salah satu pesan berikut:
AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found.]
AADSTS90002: Tenant 'cf61953b-e41a-46b3-b500-663d279ea744' not found. This may happen if there are no activesubscriptions for the tenant. Check to make sure you have the correct tenant ID. Check with your subscriptionadministrator.
Lakukan pemecahan masalah pengecualian dengan menggunakan langkah-langkah ini:
Konfirmasikan bahwa Anda menggunakan versi terbaru MSAL.NET.
Konfirmasikan bahwa host otoritas yang Anda tetapkan saat membuat aplikasi klien rahasia dan host otoritas yang Anda gunakan dengan ADAL serupa. Secara khusus, apakah cloud (Azure Pemerintah, Azure Tiongkok 21Vianet, atau Azure Jerman) sama?
MsalClientException
Di aplikasi multipenyewa, tentukan otoritas umum saat membangun aplikasi untuk menargetkan penyewa tertentu seperti, penyewa pengguna saat memanggil API web. Sejak MSAL.NET 4.37.0, saat Anda menentukan .WithAzureRegion pada pembuatan aplikasi, Anda tidak dapat lagi menentukan Otoritas menggunakan .WithAuthority selama permintaan token. Jika Anda melakukannya, Anda akan mendapatkan kesalahan berikut saat memperbarui versi MSAL.NET sebelumnya:
MsalClientException - "You configured WithAuthority at the request level, and also WithAzureRegion. This is not supported when the environment changes from application to request. Use WithTenantId at the request level instead."
Untuk mengatasi masalah ini, ganti .WithAuthority pada ekspresi AcquireTokenXXX dengan .WithTenantId. Tentukan penyewa menggunakan GUID atau nama domain.