呼叫 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://learn.microsoft.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 中的令牌快取串行化。

無訊息登入的帳戶

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

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

父視窗句柄

您必須使用 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 帳戶選擇器未傳回帳戶」訊息表示應用程式使用者關閉顯示帳戶的對話框,或對話方塊本身當機。 如果 AccountsControlWindows 控件在 Windows 中註冊不正確,就可能發生當機。 若要解決此問題:

  1. 在任務欄上,以滑鼠右鍵按兩下 [開始],然後選取 [Windows PowerShell] [管理員]。

  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。