带有 Microsoft Graph 的 AuthProvider Api "Ctor not found"

AuthProvider with Microsoft Graph Api "Ctor not found"

我正在尝试使用 Microsoft.Graph Api 获取用户列表。我能够在 api 上进行身份验证。我在登录时收到令牌和基本个人资料信息。

然后我尝试使用 Microsoft.Graph.Auth SDK/nuget found here 来生成我的请求。这是我正在尝试做的一个准系统示例(您也可以在包的文档中找到这个示例。

public void test()
{
    var clientApplication = PublicClientApplicationBuilder
        .Create(ClientId)
        .WithTenantId(TenantId)
        .Build();

    var authProvider = new IntegratedWindowsAuthenticationProvider(clientApplication);
    var graphClient = new GraphServiceClient(authProvider);

    var users = await graphClient.Users
        .Request()
        .GetAsync();
}

但是我在之前System.MissingMethodException: 'Method not found: 'Void Microsoft.Graph.Auth.IntegratedWindowsAuthenticationProvider..ctor(Microsoft.Identity.Client.IPublicClientApplication, System.Collections.Generic.IEnumerable`1<System.String>)'.'甚至进入方法test()时都得到错误System.MissingMethodException: 'Method not found: 'Void Microsoft.Graph.Auth.IntegratedWindowsAuthenticationProvider..ctor(Microsoft.Identity.Client.IPublicClientApplication, System.Collections.Generic.IEnumerable`1<System.String>)'.'。该消息说它找不到 IntegratedWindowsAuthenticationProvider 但软件包已安装,我可以毫无问题地导航到构造函数 (F12)。

如果我删除带有 IntegratedWindowsAuthenticationProvider 的行,代码将执行而不会崩溃。而且我可以成功验证到 Api。我尝试在身份验证成功后移动线路,但出现相同的错误。

Microsoft.Graph.Auth 只支持.Net 4.5,我用的是4.8。由于代码库中的其他要求,我无法降级到 4.5。我试图修改开源项目,但我 运行 陷入其他问题,所以我决定不使用这个包。我实现了一个基本解决方案,其中包含一些自己管理令牌的方法。

这里是处理缓存令牌的class

using System.IO;
using System.Security.Cryptography;
using Microsoft.Identity.Client;

namespace Overwatch.AutoCAD.Authentication
{
    static class TokenCacheHelper
    {
        static TokenCacheHelper()
        {
            CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + ".msalcache.bin3";
        }

        /// <summary>
        /// Path to the token cache
        /// </summary>
        public static string CacheFilePath { get; private set; }

        private static readonly object FileLock = new object();

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

        public static void AfterAccessNotification(TokenCacheNotificationArgs args)
        {
            // if the access operation resulted in a cache update
            if (args.HasStateChanged)
            {
                lock (FileLock)
                {
                    // reflect changesgs in the persistent store
                    File.WriteAllBytes(CacheFilePath,
                                       ProtectedData.Protect(args.TokenCache.SerializeMsalV3(),
                                                             null,
                                                             DataProtectionScope.CurrentUser)
                                      );
                }
            }
        }

        internal static void EnableSerialization(ITokenCache tokenCache)
        {
            tokenCache.SetBeforeAccess(BeforeAccessNotification);
            tokenCache.SetAfterAccess(AfterAccessNotification);
        }
    }
}

这是我修改后的初始测试方法

public async void test()
{
    AuthenticationResult authResult = await PublicClientApp
        .AcquireTokenSilent(scopes, (await PublicClientApp.GetAccountsAsync()).FirstOrDefault())
        .ExecuteAsync();
    HttpClient client = ApiHelper.CreateHttpClient("https://graph.microsoft.com/v1.0/");
    GraphServiceClient graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
    {
        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
    }));

    var users = await graphClient.Users
        .Request()
        .GetAsync();
}

您所要做的就是 link 创建客户端应用程序构建器时的 TokenCache 助手

public static void CreateApplication()
{
    var builder = PublicClientApplicationBuilder.Create(ClientId)
        .WithAuthority($"{Instance}{Tenant}")
    .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient");

    _clientApp = builder.Build();

    TokenCacheHelper.EnableSerialization(_clientApp.UserTokenCache);
}

当然,根据您的要求添加 try catches 和 fail safes。