Windows应用中MSAL无法调用Prompt.SelectAccount弹窗及跨端实现咨询
问题描述
- Windows应用集成MSAL时,使用
.WithPrompt(Prompt.SelectAccount)会出现鼠标悬停错误提示,且账户选择弹窗无法弹出,相关代码如下:
private async Task CallGraph() { var _clientApp = PublicClientApplicationBuilder.Create(id) .WithAuthority(AzureCloudInstance.AzurePublic, "somevalue") .WithDefaultRedirectUri() .Build(); string[] scopes = new string[] { "user.read" }; AuthenticationResult authResult = null; var app = _clientApp; var accounts = await app.GetAccountsAsync(); var firstAccount = accounts.FirstOrDefault(); try { authResult = await app.AcquireTokenSilent(scopes, firstAccount) .ExecuteAsync(); } catch (MsalUiRequiredException ex) { System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}"); try { authResult = await app.AcquireTokenInteractive(scopes) //.WithUseEmbeddedWebView(false) //.WithPrompt(Prompt.SelectAccount) .ExecuteAsync(); } catch (MsalException msalex) { TraceLogging.LogException($"Error Acquiring Token:{System.Environment.NewLine}{msalex}", ex); } } catch (Exception ex) { TraceLogging.LogException($"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}", ex); return; } if (authResult != null) { await GetHttpContentWithToken(graphAPIEndpoint, authResult.AccessToken); string res = $"Username: {authResult.Account.Username}" + Environment.NewLine; } } public async Task<string> GetHttpContentWithToken(string url, string token) { var httpClient = new System.Net.Http.HttpClient(); System.Net.Http.HttpResponseMessage response; try { var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url); request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); response = await httpClient.SendAsync(request); var content = await response.Content.ReadAsStringAsync(); return content; } catch (Exception ex) { return ex.ToString(); } }
- 同时需要桌面应用及非.NET Core的ASP.NET Web应用的MSAL实现示例
解决方案
一、修复Windows应用中Prompt.SelectAccount的问题
检查MSAL版本与命名空间
- 确保安装了最新稳定版的
Microsoft.Identity.ClientNuGet包,旧版本可能未包含Prompt.SelectAccount枚举 - 代码顶部必须引入命名空间:
using Microsoft.Identity.Client;,否则Prompt会被识别为未定义类型
- 确保安装了最新稳定版的
修正AcquireTokenInteractive代码
取消注释相关配置,同时确保UI线程上下文正确,调整后代码如下:authResult = await app.AcquireTokenInteractive(scopes) .WithUseEmbeddedWebView(false) // 使用系统浏览器,避免嵌入式视图的兼容性问题 .WithPrompt(Prompt.SelectAccount) .ExecuteAsync() .ConfigureAwait(true); // 确保回到UI线程弹出窗口排查其他弹窗不显示原因
- 检查Azure AD应用注册的重定向URI:Windows公共客户端应用需配置为
msal{你的ClientId}://auth格式 - 捕获更详细错误信息:在
MsalException中打印msalex.Details和msalex.ErrorCode,定位具体报错点
- 检查Azure AD应用注册的重定向URI:Windows公共客户端应用需配置为
二、桌面应用(WPF/WinForms)MSAL示例
using Microsoft.Identity.Client; using System.Linq; using System.Threading.Tasks; public class MsalDesktopHelper { private readonly IPublicClientApplication _clientApp; private const string ClientId = "你的客户端ID"; private readonly string[] _requiredScopes = new[] { "user.read" }; public MsalDesktopHelper() { _clientApp = PublicClientApplicationBuilder.Create(ClientId) .WithAuthority(AzureCloudInstance.AzurePublic, "common") .WithDefaultRedirectUri() .Build(); } public async Task<AuthenticationResult> GetValidTokenAsync() { var accounts = await _clientApp.GetAccountsAsync(); var existingAccount = accounts.FirstOrDefault(); try { // 优先尝试静默获取令牌 return await _clientApp.AcquireTokenSilent(_requiredScopes, existingAccount) .ExecuteAsync(); } catch (MsalUiRequiredException) { // 静默失败,弹出账户选择窗口 return await _clientApp.AcquireTokenInteractive(_requiredScopes) .WithPrompt(Prompt.SelectAccount) .WithUseEmbeddedWebView(false) .ExecuteAsync() .ConfigureAwait(true); } } }
三、非.NET Core的ASP.NET Web应用(Framework)MSAL示例
using Microsoft.Identity.Client; using System.Web; using System.Web.Mvc; public class AccountController : Controller { private const string ClientId = "你的客户端ID"; private const string TenantId = "你的租户ID"; private const string RedirectUri = "https://localhost:44300/Account/AuthorizationCallback"; private readonly string[] _apiScopes = new[] { "https://graph.microsoft.com/user.read" }; public ActionResult SignIn() { var pca = PublicClientApplicationBuilder.Create(ClientId) .WithAuthority($"https://login.microsoftonline.com/{TenantId}") .WithRedirectUri(RedirectUri) .Build(); // 生成授权跳转URL var authRequestUrl = pca.GetAuthorizationRequestUrl(_apiScopes) .WithPrompt(Prompt.SelectAccount) .ExecuteAsync() .Result; return Redirect(authRequestUrl.ToString()); } public async Task<ActionResult> AuthorizationCallback() { var pca = PublicClientApplicationBuilder.Create(ClientId) .WithAuthority($"https://login.microsoftonline.com/{TenantId}") .WithRedirectUri(RedirectUri) .Build(); // 通过授权码获取令牌 var authResult = await pca.AcquireTokenByAuthorizationCode(_apiScopes, Request.QueryString["code"]) .ExecuteAsync(); // 将令牌存储到Session Session["AccessToken"] = authResult.AccessToken; return RedirectToAction("Index", "Home"); } }
内容的提问来源于stack exchange,提问作者Radha
相关产品推荐
相关产品推荐

