MSAL.NET 中的令牌缓存序列化不起作用

Token cache serialization in MSAL.NET is not working

我在尝试序列化令牌缓存时遇到一些问题,return从使用 MSAL 进行身份验证。 我将不胜感激任何帮助,因为我真的不明白我做错了什么。 这是我们的 situation/problem:

我们目前使用 ADAL 来允许用户从我们的桌面应用程序对其 SharePoint Online 帐户进行身份验证,但希望切换到 MSAL。

我们已经实现了两种可能的身份验证流程。 publicClientApplication,允许用户使用其当前活动的 Microsoft 凭据进行身份验证,ConfidentialClientApplication,允许使用证书进行身份验证,如您在以下代码的 catch 块中所见:

                try
                {
                     Debugger.Launch();
                    if (certificate != null)
                    { 
                        IConfidentialClientApplication m_authContext = ConfidentialClientApplicationBuilder.Create(pClientID)
                            .WithTenantId(m_tenant).WithCertificate(certificate).WithRedirectUri(pClientRedirectURI).Build();
                        var accounts = await m_authContext.GetAccountsAsync();
                        authResult = await m_authContext.AcquireTokenSilent(m_scope, accounts.FirstOrDefault()).ExecuteAsync();
                    }
                    else
                    {
                        IPublicClientApplication m_authContext = PublicClientApplicationBuilder.Create(pClientID).WithTenantId(m_tenant).WithRedirectUri(pClientRedirectURI).Build();
                        var accounts = await m_authContext.GetAccountsAsync();
                        authResult = await m_authContext.AcquireTokenSilent(m_scope, accounts.FirstOrDefault()).ExecuteAsync();
                    }
                }
                catch
                {   
                    if (certificate != null)
                    { 
                        IConfidentialClientApplication m_authContext = ConfidentialClientApplicationBuilder.Create(pClientID)
                            .WithTenantId(m_tenant).WithCertificate(certificate).WithRedirectUri(pClientRedirectURI).Build();
                        TokenCacheHelper.EnableSerialization(m_authContext.AppTokenCache);
                        authResult = await m_authContext.AcquireTokenForClient(m_scope).WithForceRefresh(true).ExecuteAsync();
                    }
                    else
                    {
                        IPublicClientApplication m_authContext = PublicClientApplicationBuilder.Create(pClientID)
                            .WithTenantId(m_tenant).WithRedirectUri(pClientRedirectURI).Build();
                        TokenCacheHelper.EnableSerialization(m_authContext.UserTokenCache);
                        authResult = await m_authContext.AcquireTokenInteractive(m_scope).ExecuteAsync();
                    }
                } 

到目前为止,代码工作正常,初始身份验证在两种情况下都成功。 现在的问题是我们希望保留获取的令牌,以便下次用户启动我们的程序并尝试访问 SharePoint 时,他不必再次进行身份验证。但是尝试使用先前存储的令牌来验证静默是行不通的,对于 public 和机密应用程序都是如此。 然而,AfterAccessNotification 的序列化似乎确实有效,因为至少有一些东西被写入了缓存文件。但是读回这些数据不会。需要指出的一件事是 GetAccountsAsync() 将始终 return 0.

到目前为止,我从 Microsoft 文档和此处的其他问题中了解到,应用程序的内存缓存在重新创建时当然会丢失,解决方案似乎是实施 TokenCacheHelper。我们的助手 class 按照文档中的建议实现:

    static class TokenCacheHelper
    {
        public static readonly string CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + "msalcache.txt";
        private static readonly object FileLock = new object();

        public static void EnableSerialization(ITokenCache tokenCache)
        {
            Debugger.Launch();
            tokenCache.SetBeforeAccess(BeforeAccessNotification);
            tokenCache.SetAfterAccess(AfterAccessNotification);
        }

        private static void BeforeAccessNotification(TokenCacheNotificationArgs args)
        {
            args.TokenCache.DeserializeMsalV3(File.Exists(CacheFilePath)
                        ? ProtectedData.Unprotect(File.ReadAllBytes(CacheFilePath),
                                                  null,
                                                  DataProtectionScope.CurrentUser)
                       : null);
        }

        private static void AfterAccessNotification(TokenCacheNotificationArgs args)
        {
            Debugger.Launch();
            if (args.HasStateChanged)
            {
                lock (FileLock)
                {
                    // reflect changesgs in the persistent store
                    File.WriteAllBytes(CacheFilePath,
                                        ProtectedData.Protect(args.TokenCache.SerializeMsalV3(),
                                                                null,
                                                                DataProtectionScope.CurrentUser)
                                        );
                }
            }
        }

    }

我是不是对 TokenCacheHelper 或其他东西的使用有很大的误解? 还是有更简单的方法来持久化令牌缓存? 使用 ADAL 似乎要简单得多。

非常感谢您的帮助。

没有比这更简单的方法了。我自己使用的是 Mircosoft 提供的 class (TokenCacheHelper),它运行良好。我现在将令牌保留了几个星期。阅读和使用它没有问题。 一般来说,据我测试,您必须 首先 以交互方式验证您想要读取的多种数据,然后读取保存的令牌以供将来操作。你可以检查你的 Azure 安全中心,你已经对哪些数据进行了交互式身份验证或可以非交互式身份验证。

  1. 重新检查您在 Azure 安全中心读取帐户的安全设置。
  2. 重新检查范围,例如:“User.Read”、“User.ReadBasic.All”
  3. 查看 https://github.com/Azure-Samples/active-directory-dotnet-desktop-msgraph-v2 下的示例,它对我有帮助

试试吧!

PS:我会认为整个 MS-graph 库处于“测试状态”并且仍然存在错误,容易出错且未完成。所以期待现在和将来会有不同的行为。

此致

我们找出了导致问题的原因。只是 TokenCacheHelper.EnableSerialization(m_authContext.UserTokenCache); 的调用 在尝试获取令牌之前丢失。