我正在开发一个小 WPF 应用程序,它应该从 MS Graph API 查询一些数据。我想使用 SSO,所以用户不必单独登录应用程序。
该应用在已加入 Azure AD 的设备上运行。用户是 AADC 同步 AD 用户。 AAD 租户与 ADFS 联合。用户使用 Hello for Business (PIN) 或密码进行身份验证。产生的问题是一样的。
我可以确认用户通过以下方式获得了 PRT:
dsregcmd /status
AzureAdPrt: YES
以防万一:Azure AD 中的应用注册设置为“将应用程序视为公共(public)客户端”。并且配置了以下重定向 URI:
根据我找到的示例,我正在使用以下代码尝试获取访问 token 。然而
GetAccountsAsync()
方法不返回任何用户,也不抛出任何错误或异常。谁能告诉我,我在这里缺少什么?
任何帮助将非常感激!
PS:当我使用“交互式身份验证”尝试此操作时,它工作正常。
public GraphAuthProvider(string appId, string tenantId, string[] scopes)
{
_scopes = scopes;
try
{
_msalClient = PublicClientApplicationBuilder
.Create(appId)
.WithAuthority(AadAuthorityAudience.AzureAdMyOrg, true)
.WithTenantId(tenantId)
.Build();
}
catch (Exception exception)
{
_log.Error(exception.Message);
_log.Error(exception.StackTrace);
throw;
}
}
public async Task<string> GetAccessToken()
{
_log.Info("Starting 'GetAccessToken'...");
var accounts = await _msalClient.GetAccountsAsync();
_userAccount = accounts.FirstOrDefault();
// If there is no saved user account, the user must sign-in
if (_userAccount == null)
{
_log.Info("No cached accounts found. Trying integrated authentication...");
[...]
}
else
{
// If there is an account, call AcquireTokenSilent
// By doing this, MSAL will refresh the token automatically if
// it is expired. Otherwise it returns the cached token.
var userAccountJson = await Task.Factory.StartNew(() => JsonConvert.SerializeObject(_userAccount));
_log.Info($"Found cached accounts. _userAccount is: {userAccountJson}");
var result = await _msalClient
.AcquireTokenSilent(_scopes, _userAccount)
.ExecuteAsync();
return result.AccessToken;
}
}
最佳答案
能够拥有IAccounts
从 MSAL(访问缓存)返回,它必须在某个时候引导缓存。您缺少起点,在您的情况下是 AcquireTokenInteractive
.
建议在 MSAL 上使用以下 try/catch 模式:
try
{
var accounts = await _msalClient.GetAccountsAsync();
// Try to acquire an access token from the cache. If an interaction is required, MsalUiRequiredException will be thrown.
result = await _msalClient.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
catch (MsalUiRequiredException)
{
// Acquiring an access token interactively. MSAL will cache it so you can use AcquireTokenSilent on future calls.
result = await _msalClient.AcquireTokenInteractive(scopes)
.ExecuteAsync();
}
使用这个 try/catch 模式而不是你的 if/else 逻辑,你会很高兴。
为了进一步引用,有这个msal desktop samples其中涵盖了一系列常见场景。
更新
如果您在每个操作上都实例化一个新的 _msalClient,那么这就解释了为什么其他调用不起作用。您可以将 _msalClient 作为静态/单例实例,也可以实现序列化 token 缓存。 Here is a cache example
关于c# - MSAL - PublicClientApplication - GetAccountsAsync() 不返回任何帐户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62210738/