呼叫 Web API 的傳統型應用程式:使用 WAM 取得權杖

Microsoft 驗證程式庫 (MSAL) 會呼叫 Web 帳戶管理員 (WAM),這是作為驗證代理程式的 Windows 10+ 元件。 訊息代理程式讓您應用程式的使用者可受益於與 Windows 已知帳戶整合,例如您在 Windows 工作階段中登入的帳戶。

WAM 價值主張

使用驗證代理程式 (例如 WAM) 有許多優點:

  • 增強的安全性。 請參閱 權杖保護
  • 針對 Windows Hello、條件式存取和 FIDO 金鑰的支援。
  • 與 Windows 的 「電子郵件和帳戶」 檢視整合。
  • 快速單一登入。
  • 能夠使用目前的 Windows 帳戶以無訊息方式登入。
  • 錯誤修正和增強功能都會隨附於 Windows。

WAM 限制

  • WAM 可以在 Windows 10 和更新版本以及 Windows Server 2019 和更新版本上使用。 在 Mac、Linux 和舊版 Windows 上,MSAL 將自動切換回瀏覽器。
  • 不支援 Azure Active Directory B2C (Azure AD B2C) 和 Active Directory 同盟服務 (AD FS) 授權單位。 MSAL 會切換回瀏覽器。

WAM 整合套件

大部分的應用程式都需要參考 Microsoft.Identity.Client.Broker 套件才能使用此整合。 .NET MAUI 應用程式不需要這麼做,因為當目標 net6-windows 及更新版本時,功能位於 MSAL 內。

WAM 呼叫模式

您可以使用下列的 WAM 模式:

    // 1. Configuration - read below about redirect URI
    var pca = PublicClientApplicationBuilder.Create("client_id")
                    .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows))
                    .Build();

    // Add a token cache; see https://video2.skills-academy.com/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=desktop

    // 2. Find an account for silent login

    // Is there an account in the cache?
    IAccount accountToLogin = (await pca.GetAccountsAsync()).FirstOrDefault();
    if (accountToLogin == null)
    {
        // 3. No account in the cache; try to log in with the OS account
        accountToLogin = PublicClientApplication.OperatingSystemAccount;
    }

    try
    {
        // 4. Silent authentication 
        var authResult = await pca.AcquireTokenSilent(new[] { "User.Read" }, accountToLogin)
                                    .ExecuteAsync();
    }
    // Cannot log in silently - most likely Azure AD would show a consent dialog or the user needs to re-enter credentials
    catch (MsalUiRequiredException) 
    {
        // 5. Interactive authentication
        var authResult = await pca.AcquireTokenInteractive(new[] { "User.Read" })
                                    .WithAccount(accountToLogin)
                                    // This is mandatory so that WAM is correctly parented to your app; read on for more guidance
                                    .WithParentActivityOrWindow(myWindowHandle) 
                                    .ExecuteAsync();
                                    
        // Consider allowing the user to re-authenticate with a different account, by calling AcquireTokenInteractive again                                  
    }

如果訊息代理程式不存在(例如 Windows 8.1、Mac 或 Linux),MSAL 會切換回瀏覽器,其中會套用重新導向 URI 規則。

重新導向 URI

您不需要在 MSAL 中設定 WAM 重新導向 URI,但您必須在應用程式註冊中設定它們:

ms-appx-web://microsoft.aad.brokerplugin/{client_id}

權杖快取持續性

請務必保存 MSAL 權杖快取,因為 MSAL 會繼續儲存該處的識別碼權杖和帳戶中繼資料。 如需詳細資訊,請參閱 MSAL.NET 中的權杖快取序列化

無訊息登入的帳戶

若要尋找無訊息登入的帳戶,建議您使用下列模式:

  • 如果使用者先前有登入,請使用該帳戶。 如果沒有,請針對目前的 Windows 帳戶使用 PublicClientApplication.OperatingSystemAccount
  • 允許用戶以互動方式登入來變更為不同的帳戶。

父視窗控制代碼

您必須使用 WithParentActivityOrWindow API,將 MSAL 設定為互動體驗所屬的視窗。

UI 應用程式

如需 Windows Forms (WinForms)、Windows Presentation Foundation (WPF) 或 Windows UI 程式庫第 3 版(WinUI3)等 UI 應用程式,請參閱 擷取視窗控制代碼

主控台應用程式

針對主控台應用程式,因為終端機視窗及其索引標籤,因此設定更加複雜。 使用下列程式碼:

enum GetAncestorFlags
{   
    GetParent = 1,
    GetRoot = 2,
    /// <summary>
    /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
    /// </summary>
    GetRootOwner = 3
}

/// <summary>
/// Retrieves the handle to the ancestor of the specified window.
/// </summary>
/// <param name="hwnd">A handle to the window whose ancestor will be retrieved.
/// If this parameter is the desktop window, the function returns NULL. </param>
/// <param name="flags">The ancestor to be retrieved.</param>
/// <returns>The return value is the handle to the ancestor window.</returns>
[DllImport("user32.dll", ExactSpelling = true)]
static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);

[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

// This is your window handle!
public IntPtr GetConsoleOrTerminalWindow()
{
   IntPtr consoleHandle = GetConsoleWindow();
   IntPtr handle = GetAncestor(consoleHandle, GetAncestorFlags.GetRootOwner );
  
   return handle;
}

疑難排解

「WAM 帳戶選擇器未傳回帳戶」錯誤訊息

「WAM 帳戶選擇器未傳回帳戶」的訊息表示應用程式使用者已關閉顯示帳戶的對話方塊,或對話方塊本身已損毀。 如果 AccountsControl (Windows 控制項) 在 Windows 中註冊不正確,可能會發生當機。 若要解決此問題:

  1. 在工作列上,以滑鼠右鍵按一下 [開始],然後選取 [Windows PowerShell (Admin)]

  2. 如果您在 [使用者帳戶控制] 對話方塊中看到提示,請選取 [是] 以啟動 PowerShell。

  3. 複製並執行下列指令碼:

    if (-not (Get-AppxPackage Microsoft.AccountsControl)) { Add-AppxPackage -Register "$env:windir\SystemApps\Microsoft.AccountsControl_cw5n1h2txyewy\AppxManifest.xml" -DisableDevelopmentMode -ForceApplicationShutdown } Get-AppxPackage Microsoft.AccountsControl
    

在單一檔案部署期間的 「MsalClientException: ErrorCode: wam_runtime_init_failed」 錯誤訊息

將應用程式封裝成 單一檔案搭售方案時,您可能會看到下列錯誤:

MsalClientException: wam_runtime_init_failed: The type initializer for 'Microsoft.Identity.Client.NativeInterop.API' threw an exception. See https://aka.ms/msal-net-wam#troubleshooting

此錯誤表示來自 Microsoft.Identity.Client.NativeInterop 的原生二進位檔未封裝到單一檔案搭售方案中。 若要內嵌那些檔案以進行解壓縮並取得單一輸出檔案,請將 IncludeNativeLibrariesForSelfExtract 屬性設定為 true深入瞭解如何將原生二進位檔封裝到單一檔案

連線問題

如果應用程式用戶經常看到類似「請檢查您的連線並再試一次」的錯誤訊息,請參閱 Office 的疑難解答指南。 該疑難解答指南也會使用訊息代理程式。

範例

您可以在 GitHub 上找到使用 WAM 的 WPF 範例。

下一步

繼續本案例的下一篇文章:從桌面應用程式呼叫 Web API