MSAL UserTokenCache未在Android上持久化

MSAL UserTokenCache未在Android上持久化,android,xamarin.forms,azure-ad-b2c,msal,Android,Xamarin.forms,Azure Ad B2c,Msal,我曾尝试使用Azure B2C和MSAL对用户进行身份验证,但遇到了一些用户体验问题 当我调试我的应用程序时,我通常不必登录,因为我已经通过身份验证,并且令牌仍然有效。但是,如果我从Debug切换到Release,然后测试应用程序,那么AquireTokenSilentAsync方法似乎无法从UserTokenCache检索有效的令牌。我的假设是,每次关闭应用程序时,都会清除UserTokenCache。不知何故,这不会发生在调试模式下,我想这是因为缓存在部署之间是持久化的 我以这种方式获得身份

我曾尝试使用Azure B2C和MSAL对用户进行身份验证,但遇到了一些用户体验问题

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

我以这种方式获得身份验证结果,但尝试了不同的重载,但没有成功

AuthenticationResult ar=等待 App.PCApplication.AcquireTokenSilentAsyncApp.Scopes, App.Authority,App.signupsigningpolicy,false

因此,当我登录时,关闭并重新进入应用程序,我仍然需要再次登录

我完全知道MSAL仍在预览中,但我还没有找到与此行为相关的任何问题。这是一个已知问题,是否有解决方法


查看MSAL源代码,我可以清楚地看到UserTokenCache正在使用Android SharePreferences进行持久性,这在调试模式下非常有效。因此,要么这是一个bug/缺少的实现,要么我没有看到明显的东西。

我几乎能够准确地复制它。在IDE调试器下运行,它可以完美地工作,但是如果它没有连接到调试器,或者作为发布版本运行,它将以静默方式无法存储令牌,并且在尝试持久化之后出现的所有其他内容通常也无法运行

我通过实现我自己的从TokenCache派生的缓存并查看它试图做什么,在Android上解决了同样的问题

我找到了一个桌面应用程序的示例,如下所述:

然后查看了GitHub repo中定义的文件缓存:

我复制了他们的文件缓存,并将其添加到PublicClientApplication初始化中:

ClientApplication = new PublicClientApplication(SharedConstants.AuthContext, SharedConstants.ClientId)
{
  RedirectUri = "urn:ietf:wg:oauth:2.0:oob",
  UserTokenCache = new FileCache(),
};
默认情况下,大多数示例将UserTokenCache属性保留为空,以假定使用平台默认的共享pref

然后调整它,在读/写/访问过程中执行一些详细的日志记录,以查看它在做什么:

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上,它抛出了一个异常,该异常与MSAL库内部深处没有DateTimeOffset类型属性的序列化处理程序有关

一旦我将AfterAccessNotification包装在一个try-catch中,并使用一个处理程序记录异常发生的情况,它就可以正常工作了

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

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

我希望这对某人有帮助


编辑:正如@Henrik在他的评论中提到的那样:编辑项目属性并告诉它不要在Android上链接System.Runtime.Serialization.dll,然后永久性地修复问题。基于我公认的有限测试,然后可以安全地从使用FileCache切换到默认行为。

我在博客上发表了一篇文章,介绍了我为解决这个问题所做的工作:-下面提供了一个稍微不太详细的版本,作为可能的答案。谢谢!TokenCache中的Serialize方法确实引发了一个异常:System.Runtime.Serialization.InvalidDataContractException:类型为“System.Runtime.Serialization.DateTimeOffsetAdapter”的属性“OffsetMinutes”没有设置方法。有些人建议在Android项目中跳过System.Runtime.Serialization程序集的链接,这立即解决了问题。太棒了!您是否愿意/能够将此标记为答案?显然我自己做不到这一点;跳过System.Runtime.Serializaton的链接是否会在项目中的其他位置出现任何其他问题?因为这个跳过,就像任何不可行的场景一样。Thanks@Suchith我不知道,我想这将取决于你在构建什么,需要将S.R.S物理链接到你的应用程序。我怀疑不是这样,它只是意味着S.R.S在你的应用程序中作为完整的dll分发。