ADELiOS - 如何静默刷新访问令牌?
ADALiOS - how to refresh accessToken silently?
我正在使用 ADALiOS v3.0.0-pre.2 连接到 Azure AD B2C 并授权给定用户。我成功地为用户获得了 accessToken
,系统提示用户使用 UI 登录该过程。我在 ADAuthenticationContext
实例上使用 acquireTokenWithScopes
方法来执行此操作。
在某处,我想确保我之前获得的 accessToken
仍然有效并且没有被撤销。所以,我使用 acquireTokenSilentWithScopes
来检查。但是,我立即收到一条错误消息:
Error raised: 10. Additional Information: Domain: ADAuthenticationErrorDomain Details: The user credentials are need to obtain access token. Please call the non-silent acquireTokenWithResource methods.
此 API 的正确用法是什么,以便令牌在服务器端被撤销时静默刷新或抛出错误?
我通过对 ADALiOS v3.0.0-pre.2 进行以下更改成功击败 acquireTokenSilentWithScopes
提交。
更改 #1:
ADUserIdentifier 具有以下 class 方法:
+(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
,进而 return 是用户配置文件字典中的 preferred_username
值。对我而言,该值未设置。所以,userCacheKey
returns NSNull
缓存机制失效。
在用户配置文件字典中设置的值为 name
和 tid
。这可能是服务器配置错误,但我通过将此方法的 return 值更改为 _profileInfo.friendlyName
(映射到用户配置文件字典中的 name
)解决了这个问题。
更改 #3:
ADKeychainTokenCacheStore,我将其用作具体的 ADTokenCacheStoring 缓存选择,公开了一个 sharedGroup
属性 允许多个应用程序共享公共钥匙串秘密。默认情况下,sharedGroup
设置为 com.microsoft.adalcache
。但是,由于 class 当前是私有的,因此无法覆盖此值。此外,设置该值需要 iOS 应用程序在其权利中声明共享组名称。如果没有正确配置这些权利,则无法将值设置到钥匙串中。因此,为了解决此问题,我在 ADKeychainTokenCacheStore class 本身中手动将默认 sharedGroup
值设置为 nil
。我怀疑这个 class 最终会被框架公开为 public,但目前情况并非如此,所以我不得不破解它。
更改#4
当我通过 ADALiOS 框架从 AD 服务器请求身份验证令牌时,我使用了一个策略和一组范围。框架代码使用此 policy/scope 对创建查找键并查看是否已缓存该键的任何标记。如果找到 none,代码会按预期联系服务器。一旦服务器 return 获得了身份验证令牌,框架就会尝试缓存该值。它构造了一个全新的 policy/scope 键对象。然而,这一次,它使用由服务器return编辑的策略和范围值,而不是我传入的值。而且,由于某种原因,服务器return将这些值设置为 nil
。因此,为存储而构建的新 policy/scope 密钥是有效的,但与我最初用来查找缓存令牌的密钥 不同 。因此,虽然缓存操作成功,但下次我尝试使用有效的 policy/scope 对查找身份验证令牌时,查找失败了。
这可能又是服务器配置错误问题。
无论如何,为了解决这个问题,我现在将服务器响应中的策略和范围值重置为我最初用于生成服务器请求的原始值。这发生在 ADAuthenticationContext(TokenCaching)
中的以下方法中:
- (void)updateCacheToResult:(ADAuthenticationResult*)result
cacheInstance:(id<ADTokenCacheStoring>)tokenCacheStoreInstance
cacheItem:(ADTokenCacheStoreItem*)cacheItem
withRefreshToken:(NSString*)refreshToken
完成所有这些更改后,获取 AD 身份验证令牌并静默刷新它似乎按预期工作。我有点担心我需要侵入多少代码库才能让它工作。如果一些 MS 人员可以指导我是否需要进行这些更改,或者是否有更直接的解决方案,这将很有帮助。
更新:
事实证明,您不需要直接侵入 ADKeychainTokenCacheStore(更改上面的 #3)。 ADAutheticationSettings class 公开了一种方法供您这样做:
[[ADAuthenticationSettings sharedInstance] setSharedCacheKeychainGroup:nil];
我是 Azure Active Directory 团队的 Brandon Werner。我在这里回答了这个问题: 针对所问的具体问题。
我正在使用 ADALiOS v3.0.0-pre.2 连接到 Azure AD B2C 并授权给定用户。我成功地为用户获得了 accessToken
,系统提示用户使用 UI 登录该过程。我在 ADAuthenticationContext
实例上使用 acquireTokenWithScopes
方法来执行此操作。
在某处,我想确保我之前获得的 accessToken
仍然有效并且没有被撤销。所以,我使用 acquireTokenSilentWithScopes
来检查。但是,我立即收到一条错误消息:
Error raised: 10. Additional Information: Domain: ADAuthenticationErrorDomain Details: The user credentials are need to obtain access token. Please call the non-silent acquireTokenWithResource methods.
此 API 的正确用法是什么,以便令牌在服务器端被撤销时静默刷新或抛出错误?
我通过对 ADALiOS v3.0.0-pre.2 进行以下更改成功击败 acquireTokenSilentWithScopes
提交。
更改 #1:
ADUserIdentifier 具有以下 class 方法:
+(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
,进而 return 是用户配置文件字典中的 preferred_username
值。对我而言,该值未设置。所以,userCacheKey
returns NSNull
缓存机制失效。
在用户配置文件字典中设置的值为 name
和 tid
。这可能是服务器配置错误,但我通过将此方法的 return 值更改为 _profileInfo.friendlyName
(映射到用户配置文件字典中的 name
)解决了这个问题。
更改 #3:
ADKeychainTokenCacheStore,我将其用作具体的 ADTokenCacheStoring 缓存选择,公开了一个 sharedGroup
属性 允许多个应用程序共享公共钥匙串秘密。默认情况下,sharedGroup
设置为 com.microsoft.adalcache
。但是,由于 class 当前是私有的,因此无法覆盖此值。此外,设置该值需要 iOS 应用程序在其权利中声明共享组名称。如果没有正确配置这些权利,则无法将值设置到钥匙串中。因此,为了解决此问题,我在 ADKeychainTokenCacheStore class 本身中手动将默认 sharedGroup
值设置为 nil
。我怀疑这个 class 最终会被框架公开为 public,但目前情况并非如此,所以我不得不破解它。
更改#4
当我通过 ADALiOS 框架从 AD 服务器请求身份验证令牌时,我使用了一个策略和一组范围。框架代码使用此 policy/scope 对创建查找键并查看是否已缓存该键的任何标记。如果找到 none,代码会按预期联系服务器。一旦服务器 return 获得了身份验证令牌,框架就会尝试缓存该值。它构造了一个全新的 policy/scope 键对象。然而,这一次,它使用由服务器return编辑的策略和范围值,而不是我传入的值。而且,由于某种原因,服务器return将这些值设置为 nil
。因此,为存储而构建的新 policy/scope 密钥是有效的,但与我最初用来查找缓存令牌的密钥 不同 。因此,虽然缓存操作成功,但下次我尝试使用有效的 policy/scope 对查找身份验证令牌时,查找失败了。
这可能又是服务器配置错误问题。
无论如何,为了解决这个问题,我现在将服务器响应中的策略和范围值重置为我最初用于生成服务器请求的原始值。这发生在 ADAuthenticationContext(TokenCaching)
中的以下方法中:
- (void)updateCacheToResult:(ADAuthenticationResult*)result
cacheInstance:(id<ADTokenCacheStoring>)tokenCacheStoreInstance
cacheItem:(ADTokenCacheStoreItem*)cacheItem
withRefreshToken:(NSString*)refreshToken
完成所有这些更改后,获取 AD 身份验证令牌并静默刷新它似乎按预期工作。我有点担心我需要侵入多少代码库才能让它工作。如果一些 MS 人员可以指导我是否需要进行这些更改,或者是否有更直接的解决方案,这将很有帮助。
更新: 事实证明,您不需要直接侵入 ADKeychainTokenCacheStore(更改上面的 #3)。 ADAutheticationSettings class 公开了一种方法供您这样做:
[[ADAuthenticationSettings sharedInstance] setSharedCacheKeychainGroup:nil];
我是 Azure Active Directory 团队的 Brandon Werner。我在这里回答了这个问题: