调用 Web API 的桌面应用 - 使用 WAM 获取令牌
Microsoft 身份验证库 (MSAL) 可调用 Web 帐户管理器 (WAM),后者是一个充当身份验证代理的 Windows 10+ 组件。 此中转站使应用的用户可以受益于与 Windows 已知帐户(例如在 Windows 会话中登录的帐户)的集成。
WAM 价值主张
使用 WAM 等身份验证代理可带来诸多好处:
- 安全性增强。 请参阅令牌保护。
- 支持 Windows Hello、条件访问和 FIDO 密钥。
- 与 Windows 的“电子邮件和帐户”视图集成。
- 快速单一登录。
- 能够使用当前 Windows 帐户以无提示方式登录。
- Windows 附带的 Bug 修复和增强功能。
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 会继续在那里存储 ID 令牌和帐户元数据。 有关详细信息,请参阅 MSAL.NET 中的令牌缓存序列化。
用于无提示登录的帐户
若要查找用于无提示登录的帐户,建议采用以下模式:
- 如果用户以前登录过,请使用该帐户。 如果未登录过,请为当前 Windows 帐户使用
PublicClientApplication.OperatingSystemAccount
。 - 允许用户通过交互方式登录来更改为其他帐户。
父窗口句柄
必须使用 WithParentActivityOrWindow
API 配置具有交互式体验父级窗口的 MSAL。
UI 应用程序
对于 Windows 窗体 (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 帐户选取器未返回帐户”消息表明,应用程序用户关闭了显示帐户的对话框,或者该对话框本身崩溃了。 如果 Windows 控件 AccountsControl
在 Windows 中注册不正确,则可能会发生崩溃。 若要解决此问题,请执行以下操作:
在任务栏上,右键单击“开始”,然后选择“Windows PowerShell(管理员)”。
如果“用户帐户控制”对话框出现提示,请选择“是”以启动 PowerShell。
复制以下脚本,然后运行它:
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。