【问题标题】:ADALiOS - how to refresh accessToken silently?ADELiOS - 如何静默刷新访问令牌?
【发布时间】:2016-04-05 01:24:40
【问题描述】:

我正在使用 ADALiOS v3.0.0-pre.2 连接到 Azure AD B2C 并授权给定用户。我成功地为用户获得了accessToken,用户会收到 UI 提示以登录该过程。我在ADAuthenticationContext 实例上使用acquireTokenWithScopes 方法来执行此操作。

在某个地方,我想确保我之前获得的accessToken 仍然有效并且没有被撤销。所以,我使用acquireTokenSilentWithScopes 来检查。但是,我立即收到一条错误消息:

引发的错误:10。附加信息:域:ADAuthenticationErrorDomain 详细信息:用户凭据需要获取访问令牌。请调用非静默的 acquireTokenWithResource 方法。

此 API 的正确用法是什么,以便令牌在服务器端被撤销时静默刷新或引发错误?

【问题讨论】:

  • 这对我来说似乎不是问题。现在看来,该框架正在尝试使用 nil 作为将令牌数据存储在缓存中的键,但失败了。然后以后在缓存中找不到任何东西。仍在调查...但感谢您的链接 - 我很感激这个建议!
  • 您能提供日志给我们帮助调查吗?随时将它们发送到brandwe@microsoft.com
  • 感谢您的提议,@BrandonWerner!不幸的是,我无法与您共享日志。关于律师和保密协议的事情——不是我的决定。也就是说,我想出了需要改变什么才能让静默刷新调用正常工作。我将在下面发布我的发现。如果您可以查看它并让我知道我是否发现了实际的错误,我是否遇到了配置错误的服务器,或者我是否只是以一种不同的方式使用 API,那将非常有帮助它的意图。

标签: ios adal


【解决方案1】:

通过对 ADALiOS v3.0.0-pre.2 进行以下更改,我成功地击败了 acquireTokenSilentWithScopes 提交。

更改 #1:

ADUserIdentifier有如下类方法:

+(BOOL) identifier:(ADUserIdentifier*)identifier matchesInfo:(ADProfileInfo*)info

其中有以下几行代码:

NSString* matchString = [identifier userIdMatchString:info];
if (!matchString || [matchString isEqualToString:identifier.userId])
{
    return YES;
}

出于某种原因,matchString 有时会以NSNull 的形式返回,并在其上调用isEqualToString: 方法会抛出异常。我就这样改了:

id matchString = [identifier userIdMatchString:info];
if (!matchString || ![matchString isKindOfClass:[NSString class]] || [matchString isEqualToString:identifier.userId])
{
    return YES;
}

这似乎是框架中值得修复的合法错误。

更改 #2:

当从 AD 接收到令牌时,ADALiOS 会尝试将该值存储在缓存中。在某些时候,它会调用 ADTokenCacheStoreItemuserCacheKey 属性,其定义如下:

-(NSString*)userCacheKey
{
    switch (_identifierType)
    {
        case OptionalDisplayableId:
        case RequiredDisplayableId:
            return _profileInfo.username;

        case UniqueId:
            return _profileInfo.subject;
    }
}

就我而言,我使用RequiredDisplayableId 来识别用户。在上面的 switch 语句中,它转换为 _profileInfo.username,而后者又从用户配置文件字典中返回 preferred_username 值。对我来说,这个值没有设定。所以,userCacheKey 返回NSNull,缓存机制失败。

在用户配置文件字典中设置的值为nametid。这可能是服务器配置错误,但我通过将此方法的返回值更改为_profileInfo.friendlyName(映射到用户配置文件字典中的name)解决了这个问题。

更改 #3:

ADKeychainTokenCacheStore,我用作选择的具体 ADTokenCacheStoring 缓存,它公开了一个sharedGroup 属性,允许多个应用程序共享公共钥匙串秘密。默认情况下,sharedGroup 设置为 com.microsoft.adalcache。但是,由于该类当前是私有的,因此无法覆盖此值。此外,设置该值需要 iOS 应用程序在其权利中声明共享组名称。如果没有正确配置这些权利,将值设置到钥匙串中会失败。因此,为了解决这个问题,我在 ADKeychainTokenCacheStore 类本身中手动将默认 sharedGroup 值设置为 nil。我怀疑这个类最终会被框架公开,但目前情况并非如此,所以我不得不侵入它。

更改 #4

当我通过 ADALiOS 框架从 AD 服务器请求身份验证令牌时,我会使用一个策略和一组范围来执行此操作。框架代码使用此策略/范围对来创建查找键并查看该键的任何令牌是否已被缓存。如果没有找到,代码会按预期联系服务器。一旦服务器返回一个身份验证令牌,框架就会尝试缓存该值。它构造了一个全新的策略/范围关键对象。但是,这一次,它使用服务器返回的策略和范围值,而不是我传入的值。并且,出于某种原因,服务器将这些值返回给nil。因此,为存储而构建的新策略/范围键是有效的,但 与我最初用于查找缓存令牌的键不同。因此,当缓存操作成功时,下次我尝试使用我的有效策略/范围对查找身份验证令牌时,查找失败。

这又可能是服务器配置错误的问题。

无论如何,为了解决这个问题,我现在将来自服务器的响应中的策略和范围值重置为最初用于生成服务器请求的原始值。这发生在ADAuthenticationContext(TokenCaching) 中的以下方法中:

- (void)updateCacheToResult:(ADAuthenticationResult*)result
              cacheInstance:(id<ADTokenCacheStoring>)tokenCacheStoreInstance
                  cacheItem:(ADTokenCacheStoreItem*)cacheItem
           withRefreshToken:(NSString*)refreshToken 

在所有这些更改之后,获取 AD 身份验证令牌并静默刷新它似乎可以按预期工作。我有点担心我需要多少侵入代码库才能使其工作。如果一些 MS 人员可以指导我这些更改是否有必要或是否有更直接的解决方案,将会很有帮助。

更新: 事实证明,您不需要直接侵入 ADKeychainTokenCacheStore(更改上面的 #3)。 ADAutheticationSettings 类公开了一个方法供您这样做:

    [[ADAuthenticationSettings sharedInstance] setSharedCacheKeychainGroup:nil];

【讨论】:

    【解决方案2】:

    我是 Azure Active Directory 团队的 Brandon Werner。我在这里回答了这个问题:https://stackoverflow.com/a/44170226/1232116 针对所提出的具体问题。

    【讨论】:

      猜你喜欢
      • 2018-12-20
      • 2020-07-12
      • 2014-05-18
      • 2016-10-07
      • 2018-09-25
      • 2020-11-09
      • 2019-11-30
      • 2014-09-13
      • 2019-06-29
      相关资源
      最近更新 更多