我使用ADALiOS v3.0.0-pre.2连接到Azure AD B2C并授权给定用户。我成功地为用户获得了accessToken
,在此过程中,用户会收到登录UI的提示。我在ADAuthenticationContext
实例上使用了acquireTokenWithScopes
方法
在接下来的某个地方,我想确保我之前获得的accessToken
仍然有效,并且没有被撤销。因此,我使用acquireTokenSilentWithScopes
进行检查。然而,我立即得到一个错误回复:
引发错误:10。附加信息:域:ADAuthenticationErrorDomain详细信息:需要用户凭据才能获得访问令牌。请调用非静默的acquireTokenWithResource方法。
这个API的正确用法是什么?这样,令牌才会被静默刷新,或者只有在服务器端被吊销时才会抛出错误?
通过对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会尝试将该值存储在缓存中。在某个时刻,它调用ADTokenCacheStoreItem的userCacheKey
属性,该属性定义如下:
-(NSString*)userCacheKey
{
switch (_identifierType)
{
case OptionalDisplayableId:
case RequiredDisplayableId:
return _profileInfo.username;
case UniqueId:
return _profileInfo.subject;
}
}
在我的案例中,我使用RequiredDisplayableId
来识别用户。在上面的switch语句中,它转换为_profileInfo.username
,然后返回用户配置文件字典中的preferred_username
值。对我来说,这个值还没有设定。因此,userCacheKey
返回NSNull
,缓存机制失败。
在用户配置文件字典中设置的值是name
和tid
。这可能是服务器配置错误,但我通过将此方法的返回值更改为_profileInfo.friendlyName
(在用户配置文件字典中映射为name
)来解决此问题。
变更#3:
ADKeychainTokenCacheStore是我选择的具体AdTokenCacheStorage缓存,它公开了一个sharedGroup
属性,允许多个应用程序共享公共密钥链机密。默认情况下,sharedGroup
设置为com.microsoft.adalcache
。但是,由于该类当前是私有的,因此无法覆盖此值。此外,设置该值需要iOS应用程序在其权限中声明共享组名称。如果没有正确配置这些权限,则无法在密钥链中设置值。因此,为了解决这个问题,我在ADKeychainTokenCacheStore类本身中将默认的sharedGroup
值手动设置为nil
。我怀疑这个类最终会被框架公开,但目前情况并非如此,所以我不得不破解它
更改#4
当我通过ADALiOS框架从AD服务器请求身份验证令牌时,我会使用一个策略和一组作用域。框架代码使用这个策略/作用域对来创建一个查找键,并查看该键的任何令牌是否已经缓存。如果没有找到,代码将按预期联系服务器。一旦服务器返回auth令牌,框架就会尝试缓存该值。它构建了一个全新的策略/范围关键对象。然而,这一次,它使用了服务器返回的策略和范围值,而不是我传入的值。出于某种原因,服务器将这些值返回给nil
。因此,为存储构建的新策略/作用域键是有效的,但与我最初查找缓存令牌时使用的键不同。因此,当缓存操作成功时,下次我尝试使用有效的策略/作用域对查找auth令牌时,查找会失败。
这可能再次是服务器配置错误的问题。
无论如何,为了解决这个问题,我现在将服务器响应中的策略和范围值重置为最初用于生成服务器请求的原始值。这种情况发生在ADAuthenticationContext(TokenCaching)
中的以下方法中:
- (void)updateCacheToResult:(ADAuthenticationResult*)result
cacheInstance:(id<ADTokenCacheStoring>)tokenCacheStoreInstance
cacheItem:(ADTokenCacheStoreItem*)cacheItem
withRefreshToken:(NSString*)refreshToken
在所有这些更改之后,获取AD auth令牌并静默地刷新它似乎如预期的那样工作。我有点担心我需要破解多少代码才能让它发挥作用。如果一些MS人员能告诉我这些更改是否有必要,或者是否有更直接的解决方案,那将是有帮助的。
更新:事实证明,您不需要直接破解ADKeychainTokenCacheStore(更改上面的#3)。ADAuthenticationSettings类公开了一个这样做的方法:
[[ADAuthenticationSettings sharedInstance] setSharedCacheKeychainGroup:nil];
我是Azure Active Directory团队的Brandon Werner。我在这里回答了这个问题:https://stackoverflow.com/a/44170226/1232116针对所问的具体问题。