【问题标题】:AcquireTokenSilent always Failed to acquire token silentlyAcquireTokenSilent 总是 无法静默获取令牌
【发布时间】:2015-06-26 17:35:37
【问题描述】:

使用 ADAL,我有两个 AuthenticationContext,使用 SQL 中持久化的令牌缓存。

使用AcquireTokenByAuthorizationCode 它将令牌写入数据库,但是使用AcquireTokenSilent 时我总是得到

静默获取令牌失败。调用方法 AcquireToken

以下是复制问题的详细信息:

我创建了一个上下文

AuthenticationContext authContext = new AuthenticationContext(_authority, new AzureAdalCache(companyId, _entries, _unitOfWork));

然后我通过授权获取Token

authContext.AcquireTokenByAuthorizationCode(authorizationCode, new Uri(redirectUri), _clientCredential);

此时,它在数据库中保存了一个条目

如果我调用它,我会得到一个异常。

authContext.AcquireTokenSilent(_authority, _clientCredential, new UserIdentifier(companyId.ToString(), UserIdentifierType.UniqueId)).AccessToken;

我也试过同样的结果:

authContext.AcquireTokenSilent(_authority, _clientId).AccessToken;
authContext.AcquireTokenSilent(_authority, _clientCredential, UserIdentifier.AnyUser).AccessToken;

我在this Gist 中发布我的AzureAdalCache 实现。

缓存的每个条目都是like this

我错过了什么?

更新

根据@vibronet cmets 的回答,我有这个

AuthenticationContext authContext = new AuthenticationContext(_authority, new AzureAdalCache(companyId, _entries, _unitOfWork));
authContext.AcquireTokenByAuthorizationCode(authorizationCode, new Uri(redirectUri), _clientCredential, _eWSResource);
string result = authContext.AcquireTokenSilent(_eWSResource, _clientId, UserIdentifier.AnyUser).AccessToken;

【问题讨论】:

    标签: azure oauth azure-active-directory azure-webjobs adal


    【解决方案1】:

    问题是我基本上在我的应用程序中使用了 Common Authority https://login.windows.net/common/oauth2/authorize。它适用于 AcquireTokenByAuthorizationCode() 但不适用于 AcquireTokenSilent()。

    所以当调用 AcquireTokenByAuthorizationCode() 时我需要它来保存 TenantId,并且当调用 AcquireTokenSilent() 时授权使用像 https://login.windows.net/<tenant ID>/oauth2/authorize 这样的授权。这样,上面的代码就可以工作了。

    【讨论】:

    • 另请注意,在某些版本的 ADAL 中,作为 TenantId 的 GUID 和用户的 UniqueId 区分大小写,因为它们必须为小写,缓存才能正确加载它们。
    • 任何示例代码都会有所帮助。因为 AcquireTokenByAuthorizationCodeAsync 会有不同的参数。
    • 对我来说,只需将授权网址作为这个就足够了:https://login.windows.net/<tenant ID>/
    【解决方案2】:

    我听不懂电话:

    authContext.AcquireTokenSilent(
        _authority,
        _clientCredential,
        new UserIdentifier(companyId.ToString(), UserIdentifierType.UniqueId)
    ).AccessToken;
    

    UserIdentifier 必须与缓存中的值匹配,并且 CompanyID 听起来不像您为令牌返回的任何标识符。

    请查看我在另一个线程上指向您的示例,特别是在 https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet/blob/master/TodoListWebApp/Controllers/TodoListController.cs 中调用 AcquireTokenSilent 时使用的标识符

    您无法选择在该调用中使用哪个标识符,这取决于 AAD 发出的声明。您可以选择的唯一标识符是在缓存实例级别,而不是在单个 AcquireToken* 调用中。

    【讨论】:

    • 感谢@vibronet。我看我做得很糟糕。我应该使用字符串 userObjectID = ClaimsPrincipal.Current.FindFirst("schemas.microsoft.com/identity/claims/…; 但是...如何在后台作业中访问 ClaimsPrincipal.Current?我得到“对象引用未设置为对象的实例”
    • 您必须将正确的值保存在某处并将其传递:) 或者如果您想按需触发逻辑,则必须公开 Web API
    • 但是...如果我的网站中没有 Azure 身份验证,如何在网站中获得声明?我的意思是,网站中的用户是应用程序的本地用户(使用 ASP.NET Identity EntityFramework)。我允许用户为一些后台工作注册他的 azure AD,但我不会更改网站中的身份验证和声明。那么关于我应该将什么作为 UserId 传递给 AcquireTokenSilent() 有什么想法吗?
    • 你是决定什么是上下文的人。如果您有与本地帐户的用户会话,则可以仅为该本地帐户创建 ADAL 缓存实例。那时您甚至不需要在调用 acquiretokensilent 时指定用户标识符,因为没有歧义。这就是我们示例中的缓存的实际实现方式
    • 正如我在帖子中所说,我已经尝试过,结果相同。我调用 authContext.AcquireTokenByAuthorizationCode(authorizationCode, new Uri(redirectUri), _clientCredential, _eWSResource);然后 authContext.AcquireTokenSilent(_eWSResource, _clientId);它没有说我应该调用 AcquireToken()。我没有传递用户 ID,但 TokenCache 接收“用户 ID”作为参数。
    【解决方案3】:

    检查令牌是否存在于缓存中,否则退出并要求用户登录。

    AuthenticationContext authContext = new AuthenticationContext(Startup.Authority,
                            new NaiveSessionCache(userObjectID));
                        if (authContext.TokenCache.Count == 0)
                        {
                            authContext.TokenCache.Clear();
                            CosmosInterface.Utils.AuthenticationHelper.token = null;
                            HttpContext.GetOwinContext().Authentication.SignOut(
                                OpenIdConnectAuthenticationDefaults.AuthenticationType,
                                CookieAuthenticationDefaults.AuthenticationType);
                        }
    

    【讨论】:

      【解决方案4】:

      我在 ASPNetCore (1.0) 中遇到了同样的问题,原因是我在登录后没有存储身份验证令牌。我通过在 Startup 类中添加 OnAuthorizationCodeReceived 并将我的响应类型更改为 @987654323 来解决它@。

      希望对你有帮助。

      示例: https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore/blob/aspnet10/WebApp-WebAPI-OpenIdConnect-DotNet/Startup.cs#L100

      【讨论】:

      • 链接失效
      • 已修复@KevinR。
      【解决方案5】:

      这是一个老问题 - 但对我来说,我需要清除客户端上的 cookie,然后它迫使浏览器重新进行身份验证,一切都很好了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-10
        • 1970-01-01
        • 2016-07-12
        • 2016-08-12
        • 2017-10-08
        • 1970-01-01
        • 2023-03-10
        相关资源
        最近更新 更多