【问题标题】:MSAL - PublicClientApplication - GetAccountsAsync() doesn't return any AccountsMSAL - PublicClientApplication - GetAccountsAsync() 不返回任何帐户
【发布时间】:2020-09-24 09:19:32
【问题描述】:

我正在开发一个小 WPF 应用程序,它应该从 MS Graph API 查询一些数据。我想使用 SSO,所以用户不必单独登录应用程序。

该应用在已加入 Azure AD 的设备上运行。用户是 AADC 同步 AD 用户。 AAD 租户与 ADFS 联合。用户使用 Hello for Business (PIN) 或密码进行身份验证。产生的问题是一样的。

我可以确认用户通过以下方式获得了 PRT:

dsregcmd /status

AzureAdPrt: YES

以防万一:Azure AD 中的应用注册设置为“将应用程序视为公共客户端”。并且配置了以下重定向 URI:

根据我找到的示例,我正在使用以下代码尝试获取访问令牌。但是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;
    }
}

【问题讨论】:

    标签: c# azure-active-directory single-sign-on azure-ad-graph-api msal


    【解决方案1】:

    为了能够从 MSAL(访问缓存)返回 IAccounts,它必须在某个时候引导缓存。您错过了起点,在您的情况下是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 作为静态/单例实例,也可以实现序列化令牌缓存。 Here is a cache example

    【讨论】:

    • 感谢蒂亚戈的回复。不幸的是,这没有帮助。即使我以交互方式登录一次,以后的尝试也不会返回任何帐户。它总是想要交互式身份验证。
    • 如果您在每个操作上都实例化一个新的 _msalClient,那么这就解释了为什么其他调用不起作用。您可以将 _msalClient 作为静态/单例实例,也可以实现通用令牌缓存:github.com/Azure-Samples/…
    • 实际上,我希望我可以在不与用户部分进行任何交互的情况下对用户进行身份验证。由于用户在加入 Azure AD 的计算机上,这应该是可能的。例如,当我浏览到 portal.office.com 时,不需要任何身份验证。文档:docs.microsoft.com/en-us/azure/active-directory/devices/…,尤其是这个图表给人的印象是,它应该是可能的
    • 您可能希望在 MSAL 上使用集成 Windows 身份验证,然后:docs.microsoft.com/en-us/azure/active-directory/develop/…
    • IWA 仅在 DC 可用时才有效。但我得到的印象是,它并没有像我希望的那样工作。无论如何,缓存令牌是有效的,而且当序列化令牌过期时,它似乎可以静默刷新。所以我会同意的。感谢您的支持!您介意将令牌缓存注释添加到您的答案中,然后我会将其标记为已接受。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-02
    • 2018-10-11
    • 2023-03-22
    相关资源
    最近更新 更多