ADAL.NET 與 MSAL.NET 應用程式之間的差異

將您的應用程式從使用 ADAL 移轉至使用 MSAL 有安全性和復原的優點。 本文概述 MSAL.NET 與 ADAL.NET 之間的差異。 在大部分情況下,您想使用 MSAL.NET 和 Microsoft 身分識別平台,也就是最新一代的 Microsoft 驗證程式庫。 使用 MSAL.NET 取得權杖,以供使用者利用 Azure AD (公司和學校帳戶)、Microsoft (個人) 帳戶 (MSA) 或 Azure AD B2C 登入您的應用程式。

如果您已經熟悉 ADAL.NET 和適用於開發人員 (v1.0) 端點的 Azure AD,請了解Microsoft 身分識別平台有何不同?。 如果您的應用程式需要使用舊版的 Active Directory 同盟服務 (ADFS) 登入使用者,您仍然需要使用 ADAL.NET。 如需詳細資訊,請參閱 ADFS 支援

ADAL NET MSAL NET
NuGet 套件和命名空間 ADAL 取用自 Microsoft.IdentityModel.Clients.ActiveDirectory NuGet 套件。 命名空間為 Microsoft.IdentityModel.Clients.ActiveDirectory 新增 Microsoft.Identity.Client NuGet 封裝,並使用 Microsoft.Identity.Client 命名空間。 如果您要建置機密用戶端應用程式,請查看 Microsoft.Identity.Web
範圍和資源 ADAL.NET 會取得資源的權杖。 MSAL.NET 會取得範圍的權杖。 數個 MSAL.NET AcquireTokenXXX 覆寫需要稱為範圍 (IEnumerable<string> scopes) 的參數。 此參數是簡單的字串清單,其會宣告要求的權限和資源。 知名的範圍是 Microsoft Graph 的範圍。 您也可以使用 MSAL.NET 存取 v1.0 資源
核心類別 ADAL.NET 使用 AuthenticationContext 作為您透過授權單位連線至 Security Token Service (STS) 或授權伺服器的表示法。 MSAL.NET 的設計是以用戶端應用程式為主。 其會定義公用用戶端應用程式的 IPublicClientApplication 介面和機密用戶端應用程式的 IConfidentialClientApplication,以及這兩個類型應用程式通用合約的基底介面 IClientApplicationBase
權杖取得 在公用用戶端中,ADAL 會對驗證呼叫使用 AcquireTokenAsyncAcquireTokenSilentAsync 在公用用戶端中,MSAL 會對相同的驗證呼叫使用 AcquireTokenInteractiveAcquireTokenSilent。 這些參數與 ADAL 的參數不同。

在機密用戶端應用程式中,視案例而定,會有具有明確名稱的權杖取得方法。 另一個差異是在 MSAL.NET 中,您不必再於每次 AcquireTokenXX 呼叫中傳入應用程式的 ClientIDClientID 只會在建置 IPublicClientApplicationIConfidentialClientApplication 時設定一次。
IAccount 和 IUser ADAL 會透過 IUser 介面定義使用者的概念。 但是,使用者是人工或軟體代理程式。 如此一來,使用者可以在 Microsoft 身分識別平台中擁有一或多個帳戶,(數個 Azure AD 帳戶、Azure AD B2C、Microsoft 個人帳戶)。 使用者也可以負責一或多個 Microsoft 身分識別平台帳戶。 MSAL.NET 會定義帳戶的概念 (透過 IAccount 介面)。 IAccount 介面代表單一帳戶的相關資訊。 使用者可以在不同的租用戶中有多個帳戶。 MSAL.NET 在來賓案例中提供更好的資訊,因為提供了主帳戶資訊。 您可以閱讀更多有關 IUser 和 IAccount 之間差異的資訊。
快取持續性 ADAL.NET 可讓您使用 BeforeAccessBeforeWrite 方法擴充 TokenCache 類別,以在沒有安全儲存體的平台 (.NET Framework 和 .NET Core) 上實作所需的持續性功能。 如需詳細資訊,請參閱 ADAL.NET 中的權杖快取序列化 MSAL.NET 讓權杖快取成為密封類別,並移除其延伸模組。 因此,您的權杖快取持續性實作必須為協助程式類別的形式,其可與密封權杖快取進行互動。 MSAL.NET 中的權杖快取序列化文章中會描述此互動。 公用用戶端應用程式的序列化 (請參閱公用用戶端應用程式的權杖快取),與機密用戶端應用程式的序列化 (請參閱 Web 應用程式或 Web API 的權杖快取) 不同。
通用授權單位 ADAL 使用 Azure AD v1.0。 Azure AD v1.0 中的 https://login.microsoftonline.com/common 授權 (ADAL 使用),可讓使用者使用任何 AAD 組織 (公司或學校) 帳戶來登入。 Azure AD v1.0 不允許使用 Microsoft 個人帳戶登入。 如需詳細資訊,請參閱 ADAL.NET 中的授權驗證 MSAL 使用 Azure AD v2.0。 Azure AD v2.0 中的 https://login.microsoftonline.com/common 授權 (MSAL 使用),可讓使用者使用任何 AAD 組織 (公司或學校) 帳戶或 Microsoft 個人帳戶來登入。 若要在 MSAL 中限制僅使用組織帳戶 (公司或學校帳戶) 登入,您必須使用 https://login.microsoftonline.com/organizations 端點。 如需詳細資訊,請參閱公用用戶端應用程式中的 authority 參數。

支援的授與

以下是針對公用和機密用戶端應用程式,比較 MSAL.NET 和 ADAL.NET 支援的授與的摘要。

公用用戶端應用程式

下圖摘要說明公用用戶端應用程式的 ADAL.NET 和 MSAL.NET 之間的部分差異。

Screenshot showing some of the differences between ADAL.NET and MSAL.NET for a public client application.

以下是 ADAL.NET 和 MSAL.NET 中針對傳統型和行動應用程式支援的授與。

授與 MSAL.NET ADAL.NET
互動式 在 MSAL.NET 中以互動方式取得權杖 互動式驗證
整合式 Windows 驗證 整合式 Windows 驗證 Windows (Kerberos) 上的整合式驗證
使用者名稱/密碼 使用者名稱-密碼驗證 以使用者名稱和密碼取得權杖
裝置代碼流程 裝置碼流程 裝置 (不具網頁瀏覽器) 的裝置設定檔

機密用戶端應用程式

下圖摘要說明機密用戶端應用程式的 ADAL.NET 和 MSAL.NET 之間的部分差異。

Screenshot showing some of the differences between ADAL.NET and MSAL.NET for a confidential client application.

以下是 ADAL.NET、MSAL.NET 和適用於 Web 應用程式的 Microsoft.Identity.Web、Web API 和精靈應用程式中支援的授與。

應用程式類型 授與 MSAL.NET ADAL.NET
Web 應用程式、Web API、精靈 用戶端認證 MSAL.NET 中的用戶端認證流程 ADAL.NET 中的用戶端認證流程
Web API 代表 在 MSAL.NET 中代表 使用 ADAL.NET 代表使用者進行服務對服務呼叫
Web 應用程式 授權碼 在採用 MSAL.NET 的 Web 應用程式上取得包含授權碼的權杖 在採用 ADAL.NET 的 Web 應用程式上取得包含授權碼的權杖

使用重新整理權杖從 ADAL 2.x 移轉

在 ADAL.NET v2.X 中,公開重新整理權杖,可讓您開發有關使用這些權杖的解決方案,其做法是快取這些權杖並使用 ADAL 2.x 所提供的 AcquireTokenByRefreshToken 方法。

其中有些解決方案會使用於下列案例:

  • 長時間執行的服務,其會在使用者不再連線/登入應用程式時,執行包括為使用者重新整理儀表板的動作。
  • Web 伺服陣列案例,用於讓用戶端將重新整理權杖帶入 Web 服務 (快取是在用戶端完成、加密的 Cookie,而不是伺服器端)。

基於安全性理由,MSAL.NET 不會公開重新整理權杖。 MSAL 會為您處理重新整理權杖的程序。

幸運的是,MSAL.NET 有 API 可讓您將先前的重新整理權杖 (使用 ADAL 取得) 移轉至 IConfidentialClientApplication

/// <summary>
/// Acquires an access token from an existing refresh token and stores it and the refresh token into
/// the application user token cache, where it will be available for further AcquireTokenSilent calls.
/// This method can be used in migration to MSAL from ADAL v2 and in various integration
/// scenarios where you have a RefreshToken available.
/// (see https://aka.ms/msal-net-migration-adal2-msal2)
/// </summary>
/// <param name="scopes">Scope to request from the token endpoint.
/// Setting this to null or empty will request an access token, refresh token and ID token with default scopes</param>
/// <param name="refreshToken">The refresh token from ADAL 2.x</param>
IByRefreshToken.AcquireTokenByRefreshToken(IEnumerable<string> scopes, string refreshToken);

使用這個方法,您可提供先前所用的重新整理權杖,以及您想要的任何範圍 (資源)。 此重新整理權杖會換成新的重新整理權杖,並快取到您的應用程式中。

由於這個方法主要用於非典型案例,若未先將其轉換為 IByRefreshToken,則無法使用 IConfidentialClientApplication 立即存取。

以下程式碼片段顯示機密用戶端應用程式中的一些移轉程式碼。

TokenCache userCache = GetTokenCacheForSignedInUser();
string rt = GetCachedRefreshTokenForSignedInUser();

IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create(clientId)
 .WithAuthority(Authority)
 .WithRedirectUri(RedirectUri)
 .WithClientSecret(ClientSecret)
 .Build();
IByRefreshToken appRt = app as IByRefreshToken;

AuthenticationResult result = await appRt.AcquireTokenByRefreshToken(null, rt)
                                         .ExecuteAsync()
                                         .ConfigureAwait(false);

GetCachedRefreshTokenForSignedInUser 會擷取由舊版應用程式存放於某個儲存體,且用來使用 ADAL 2.x 的重新整理權杖。 GetTokenCacheForSignedInUser 會將已登入使用者的快取還原序列化 (因為機密用戶端應用程式的每位使用者都應該有一個快取)。

當新的重新整理權杖儲存在快取中時,會在 AuthenticationResult 值中傳回存取權杖和識別碼權杖。 您也可以將這個方法使用於您有重新整理權杖可用的各種整合案例。

v1.0 和 v2.0 權杖

有兩個版本的權杖:v1.0 權杖和 v2.0 權杖。 v1.0 端點 (ADAL 所使用) 會發出 v1.0 識別碼權杖,而 v2.0 端點 (MSAL 所使用) 會發出 v2.0 識別碼權杖。 不過,這兩個端點都會發出 Web API 所接受權杖版本的存取權杖。 Web API 的應用程式資訊清單屬性可讓開發人員選擇要接受哪個版本的權杖。 請參閱應用程式資訊清單參考文件中的 accessTokenAcceptedVersion

如需 v1.0 和 v2.0 存取權杖的詳細資訊,請參閱 Azure Active Directory 存取權杖

例外狀況

互動必要例外狀況

使用 MSAL.NET 時,您會如 AcquireTokenSilent 所述攔截 MsalUiRequiredException

catch(MsalUiRequiredException exception)
{
 try {"try to authenticate interactively"}
}

如需詳細資料,請參閱處理 MSAL.NET 中的錯誤和例外狀況

ADAL.NET 有較不明確的例外狀況。 例如,在 ADAL 中無訊息驗證失敗時,程序是攔截例外狀況並尋找 user_interaction_required 錯誤碼:

catch(AdalException exception)
{
 if (exception.ErrorCode == "user_interaction_required")
 {
  try
  {“try to authenticate interactively”}}
 }
}

如需詳細資訊,請參閱使用 ADAL.NET 在公用用戶端應用程式中取得權杖的建議模式

提示行為

MSAL.NET 中的提示行為相當於 ADAL.NET 中的提示行為:

ADAL.NET MSAL.NET Description
PromptBehavior.Auto NoPrompt Azure AD 會選擇最佳的行為 (以無訊息方式登入使用者,如果使用者只使用一個帳戶登入,則無訊息地將使用者登入,或如果使用者使用數個帳戶登入,則顯示帳戶選取器)。
PromptBehavior.Always ForceLogin 重設登入方塊,並強制使用者重新輸入其認證。
PromptBehavior.RefreshSession Consent 強制使用者再次同意所有權限。
PromptBehavior.Never Never 請勿使用;相反地,請針對公用用戶端應用程式使用建議的模式
PromptBehavior.SelectAccount SelectAccount 顯示帳戶選取器,並強制使用者選取帳戶。

處理宣告挑戰例外狀況

有時候,在取得權杖的時候,如果資源需要更多來自使用者的宣告 (例如雙因素驗證),Azure AD 會擲回例外狀況。

在 MSAL.NET 中,宣告挑戰例外狀況會以下列方式處理:

  • Claims 會在 MsalServiceException 中呈現。
  • .WithClaim(claims) 方法可套用至 AcquireTokenXXX 產生器。

如需詳細資訊,請參閱處理 MsalUiRequiredException

在 ADAL.NET 中,宣告挑戰例外狀況會以下列方式處理:

  • AdalClaimChallengeException 是例外狀況 (衍生自 AdalServiceException)。 Claims 成員包含某些具有預期宣告的 JSON 片段。
  • 接收此例外狀況的公用用戶端應用程式需要呼叫具有 claims 參數的 AcquireTokenInteractive 覆寫。 這個 AcquireTokenInteractive 覆寫甚至不會嘗試叫用快取,因為沒必要這麼做。 原因是快取中的權杖沒有正確的宣告 (否則就不會擲出 AdalClaimChallengeException)。 因此,不需要查看快取。 ClaimChallengeException 可以在進行 OBO 的 WebAPI 中接收,但 AcquireTokenInteractive 則需要在呼叫此 Web API 的公用用戶端應用程式中呼叫。

如需詳細資訊 (包括範例),請參閱處理 AdalClaimChallengeException

範圍

ADAL 使用具有 resourceId 字串的資源概念,但 MSAL.NET 使用範圍。 Azure AD 使用的邏輯如下所示:

  • 若為具有 v1.0 存取權杖 (唯一可能) 的 ADAL (v1.0) 端點,則 aud=resource
  • 若為要求資源存取權杖並接受 v2.0 權杖的 MSAL (v2.0 端點),則 aud=resource.AppId
  • 若為要求接受 v1.0 存取權杖資源的 MSAL (v2.0 端點),Azure AD 從要求的範圍剖析所需的對象。 這是藉由取得最後一個斜線之前的所有內容,並使用其作為資源識別碼來完成。 因此,如果 https://database.windows.net 預期的是對象 https://database.windows.net/,您必須要求 https://database.windows.net//.default 的範圍 (注意 ./default 前的雙斜線)。 這會在以下的範例 1 和 2 中說明。

範例 1

如果您想要為接受 v1.0 權杖的應用程式取得權杖 (例如 Microsoft Graph API,其為 https://graph.microsoft.com),您必須使用該資源所需的 OAuth2 權限來串連所需的資源識別碼,以建立 scopes

例如,若要透過應用程式識別碼 URI 為 ResourceId 的 v1.0 Web API 存取使用者的名稱,您可以使用:

var scopes = new [] { ResourceId+"/user_impersonation" };

如果您要使用 Microsoft Graph API (https://graph.microsoft.com/) 對 MSAL.NET Azure Active Directory 進行讀取和寫入,您會建立如下列程式碼片段中所示的範圍清單:

string ResourceId = "https://graph.microsoft.com/"; 
string[] scopes = { ResourceId + "Directory.Read", ResourceId + "Directory.Write" }

範例 2

如果 resourceId 的結尾有 '/',在寫入範圍值時,您必須有雙反斜線 '/'。 例如,如果您想要寫入對應至 Azure Resource Manager API (https://management.core.windows.net/) 的範圍,請要求下列範圍 (請注意有兩個斜線)。

var resource = "https://management.core.windows.net/"
var scopes = new[] {"https://management.core.windows.net//user_impersonation"};
var result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();

// then call the API: https://management.azure.com/subscriptions?api-version=2016-09-01

這是因為 Resource Manager API 預期其對象宣告 (aud) 中有一個斜線,還有一個斜線用來分隔 API 名稱與範圍。

如果您想要取得 v1.0 應用程式所有靜態範圍的權杖,您可以建立範圍清單,如下列程式碼片段所示:

ResourceId = "someAppIDURI";
var scopes = new [] { ResourceId+"/.default" };

針對用戶端認證流程,要傳遞的範圍也會是 /.default。 此範圍會讓 Azure AD 知道系統管理員在應用程式註冊時同意的所有應用程式層級權限。

後續步驟

將您的應用程式從 ADAL 移轉至 MSAL移轉您的 ADAL.NET 機密用戶端應用程式以使用 MSAL.NET