2016-11-07 88 views
2

我试图使用Azure B2C和MSAL对用户进行身份验证,但遇到了一些用户体验问题。MSAL UserTokenCache未在Android上持久保存

当我调试我的应用程序时,我通常不必登录,因为我已经过身份验证,令牌仍然有效。但是,如果我从Debug切换到Release,然后测试应用程序,AquireTokenSilentAsync方法似乎无法从UserTokenCache中检索到有效的标记。我的假设是每次关闭应用程序时都会清除UserTokenCache。不知何故,这在调试模式下不会发生,我想这是因为缓存在部署之间持续存在。

我以这种方式获得验证结果,但尝试过不同的重载没有任何成功。

AuthenticationResult AR =等待 App.PCApplication.AcquireTokenSilentAsync(App.Scopes, “”, App.Authority,App.SignUpSignInpolicy,FALSE);

所以,当我登录时,关闭并重新输入应用程序,我仍然需要重新登录。

我完全知道MSAL仍处于预览状态,但我一直未能找到与此行为有关的任何问题。这是一个已知问题,是否有解决方法?

查看MSAL源代码,我可以清楚地看到UserTokenCache正在使用Android SharePreferences进行持久保存,并且这在调试模式下可以很好地工作。所以,无论这是一个错误/缺少实现,或者我没有看到明显的东西..

+0

我已经做了一篇关于我在这里弄清楚这个问题的博客文章:http://blog.wislon.io/posts/2016/12/05/msal-token-not-stored-on- android - 稍微不太详细的版本作为下面的潜在答案提供。 – wislon

回答

4

我能够复制这几乎完全。在IDE调试器下运行,它可以很好地工作,但如果它没有连接到调试器,或者作为发布版本运行,它将默默无法存储该令牌,并且尝试持久性后的所有其他操作通常也无法运行。

我设法通过实现我自己的缓存来源于TokenCache并查看它试图做什么来解决Android上的这个相同问题。

我所在的例子为一个桌面应用程序,如下所述:

https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-native-dotnet

,然后看了一下他们的FileCache因为它是在他们的GitHub库定义:

https://github.com/AzureADQuickStarts/B2C-NativeClient-DotNet/blob/complete/TaskClient/FileCache.cs

我复制了他们的FileCache,并将其添加到PublicClientApplication初始化:

ClientApplication = new PublicClientApplication(SharedConstants.AuthContext, SharedConstants.ClientId) 
{ 
    RedirectUri = "urn:ietf:wg:oauth:2.0:oob", 
    UserTokenCache = new FileCache(), 
}; 

(默认情况下,大多数示例将UserTokenCache属性保留为空,以推测使用平台默认共享首选项)。

然后扭捏它做一些详细的日志记录在读/写/只访问,看看它是什么达:

private void AfterAccessNotification(TokenCacheNotificationArgs args) 
{ 
    // if the access operation resulted in a cache update 
    try 
    { 
    this.Log().Debug("About to update token cache (if it's changed)..."); 
    if (this.HasStateChanged) 
    { 
     this.Log().Debug("State has changed, updating cache file..."); 
     lock (FileLock) 
     { 
     // reflect changes in the persistent store 
     _file.WriteAllBytes(CacheFilePath, this.Serialize()); 
     // once the write operation took place, restore the HasStateChanged bit to false 
     this.HasStateChanged = false; 
     } 
     this.Log().Debug("Token cache file updated"); 
    } 
    this.Log().Debug("Finished updating token cache file"); 
    } 
    catch (Exception ex) 
    { 
    this.Log().ErrorException($"Something went wrong during token AfterAccessNotification: {ex.Message}", ex); 
    } 
} 

的记录显示,在Android上,它被扔涉及有异常不是一个DateTimeOffset类型属性的序列化处理程序,它位于MSAL库的深处。

一旦我将AfterAccessNotification封装在try-catch中并使用处理程序记录发生了异常,它就完全开始工作。

我一直坚持使用这个版本的FileCache现在,因为它大多解决了我目前的问题,但它确实意味着认证令牌等现在不能安全存储。

我怀疑同样的问题发生在模拟器上的iOS 10.x上,但我还没有能够验证这一点。

我希望这可以帮助别人。

编辑:作为@Henrik在他的评论中提到:编辑项目属性,并告诉它到Android上System.Runtime.Serialization.dll链接,然后永久解决该问题。根据我的(公认的)有限的测试,可以安全地从使用FileCache再次转换为默认行为。

+1

谢谢! TokenCache中的Serialize方法确实会引发异常:System.Runtime.Serialization.InvalidDataContractException:类型为“System.Runtime.Serialization.DateTimeOffsetAdapter”的属性'OffsetMinutes'没有设置方法。有人建议跳过链接Android项目中的System.Runtime.Serialization程序集,这立即解决了这个问题。 –

+0

太棒了!你会愿意还是能够将此标记为答案?显然我不能自己做这个;) – wislon

+0

跳过“System.Runtime.Serializaton”的链接是否会给项目中的其他任何问题带来任何其他问题?像任何不可行的情况,因为这个跳过。谢谢 – Suchith