You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移AD Graph与MSAL授权代码:迁移后委托权限及编译报错问题

Azure AD Graph迁移至Microsoft Graph API及MSAL.NET的问题与解决

背景

将使用Azure AD Graph和MSAL授权的应用迁移至新版Microsoft Graph API和MSAL.NET,原获取用户直接下属的代码如下:

public async Task<List<Microsoft.Azure.ActiveDirectory.GraphClient.User>> GetDirectReports(string objectId) 
{ 
    List<Microsoft.Azure.ActiveDirectory.GraphClient.User> reports = new List<Microsoft.Azure.ActiveDirectory.GraphClient.User>(); 
    try 
    { 
        var client = AuthenticationHelper.GetClient(); 
        IUser user = await client.Users.GetByObjectId(objectId).ExecuteAsync(); 
        var userFetcher = user as IUserFetcher; 
        IPagedCollection<IDirectoryObject> directReports = await userFetcher.DirectReports.ExecuteAsync(); 
        do 
        { 
            List<IDirectoryObject> directoryObjects = directReports.CurrentPage.ToList(); 
            foreach (IDirectoryObject directoryObject in directoryObjects) 
            { 
                if (directoryObject is Microsoft.Azure.ActiveDirectory.GraphClient.User) 
                { 
                    reports.Add((Microsoft.Azure.ActiveDirectory.GraphClient.User)directoryObject); 
                } 
            } 
            directReports = await directReports.GetNextPageAsync(); 
        } while (directReports != null); 
    } 
    catch (Exception e) 
    { 
        if (Request.QueryString["reauth"] == "True") 
        { 
            HttpContext.GetOwinContext()
                .Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType); 
        } 
        ViewBag.ErrorMessage = "Authorization error occurred."; 
    } 
}

迁移后的代码尝试

尝试迁移后的获取直接下属代码:

public async Task<List<User>> GetDirectReports(string userId)
{
    List<User> reports = new List<User>();
    try
    {
        var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
        {
            var token = await GetAccessTokenAsync();
            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        }));

        var directReports = await graphClient.Users[userId].DirectReports.Request().GetAsync();
        do
        {
            foreach (var report in directReports.CurrentPage)
            {
                if (report is User user)
                {
                    reports.Add(user);
                }
            }
            directReports = directReports.NextPageRequest != null ? await directReports.NextPageRequest.GetAsync() : null;
        } while (directReports != null);
    }
    catch (ServiceException ex)
    {
        if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
        {
            // Handle reauthorization logic
        }
        else
        {
            throw;
        }
    }
    return reports;
}

SharePoint认证授权代码(startauth.cs)

app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = clientId,
                    Authority = Authority,
                    RedirectUri = postLogoutRedirectUri,
                    PostLogoutRedirectUri = postLogoutRedirectUri,
                    Scope = $"openid profile {scopes}", // Include Microsoft Graph scopes
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        RoleClaimType = "roles",
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthorizationCodeReceived = async (context) =>
                        {
                            var code = context.Code;
                            var userObjectId = context.AuthenticationTicket.Identity.FindFirst(
                                "http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

                            IConfidentialClientApplication Iconfidentialapp;

                            if (!string.IsNullOrEmpty(certName))
                            {
                                // Load the certificate
                                X509Certificate2 cert = LoadCertificate(certName);
                                if (cert == null)
                                {
                                    throw new Exception("Certificate not found.");
                                }

                                // Create the confidential client application with the certificate
                                Iconfidentialapp = ConfidentialClientApplicationBuilder.Create(clientId)
                                    .WithAuthority(Authority)
                                    .WithCertificate(cert)
                                    .Build();
                            }
                            else
                            {
                                // Create the confidential client application with the client secret
                                Iconfidentialapp = ConfidentialClientApplicationBuilder.Create(clientId)
                                    .WithAuthority(Authority)
                                    .WithClientSecret(clientSecret)
                                    .Build();
                            }

                            // Acquire a token using the authorization code
                            var result = await Iconfidentialapp.AcquireTokenByAuthorizationCode(scopes.Split(' '), code)
                                .ExecuteAsync();

                            // Store the token in a helper class or session
                            AuthenticationHelper.token = result.AccessToken;
                        }
                    }
                });

遇到的错误

  • 错误CS1061:DirectReportsRequestBuilder 不包含 Request 的定义,也找不到可接受第一个参数为DirectReportsRequestBuilder类型的扩展方法Request(是否缺少 using 指令或程序集引用?)
  • 错误CS0246:找不到类型或命名空间名称DelegateAuthenticationProvider(是否缺少 using 指令或程序集引用?)

问题分析与解决方案

这两个错误均源于使用了Microsoft Graph SDK v5.x但沿用了v4.x的API写法,v5.x对SDK做了大幅简化和变更,以下是针对性修复:

1. 修复DelegateAuthenticationProvider不存在的问题

v5.x已移除DelegateAuthenticationProvider,可直接通过匿名函数传递token初始化GraphServiceClient:

var graphClient = new GraphServiceClient(async requestMessage =>
{
    var token = await GetAccessTokenAsync();
    requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
});

2. 修复DirectReports.Request()不存在的问题

v5.x中获取直接下属的语法已简化,无需.Request()方法,同时分页逻辑推荐使用PageIterator处理:

public async Task<List<User>> GetDirectReports(string userId)
{
    List<User> reports = new List<User>();
    try
    {
        var graphClient = new GraphServiceClient(async requestMessage =>
        {
            var token = await GetAccessTokenAsync();
            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        });

        // 使用PageIterator处理分页
        var pageIterator = PageIterator<User, DirectoryObjectCollectionResponse>
            .CreatePageIterator(
                graphClient,
                await graphClient.Users[userId].DirectReports.GetAsync(),
                (report) =>
                {
                    if (report is User user)
                    {
                        reports.Add(user);
                    }
                    return true;
                });

        await pageIterator.IterateAsync();
    }
    catch (ServiceException ex)
    {
        if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
        {
            // 实现重新授权逻辑
            HttpContext.GetOwinContext()
                .Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
        }
        else
        {
            throw;
        }
    }
    return reports;
}

3. 权限与依赖补充

  • 权限配置:确保Azure AD应用已添加正确的Microsoft Graph权限,委托权限可选User.Read.All或Directory.Read.All,并已完成管理员同意(如需)。
  • 依赖包:确认项目安装了最新版Microsoft Graph SDK:
    Install-Package Microsoft.Graph
    Install-Package Microsoft.Identity.Client
    
  • Scope设置:在startauth.cs中确保scopes包含Graph权限,例如:
    string scopes = "https://graph.microsoft.com/User.Read.All";
    

迁移正确性说明

你的迁移方向是正确的,只需适配Microsoft Graph SDK v5.x的API变更即可完成迁移,核心调整包括认证方式简化、请求语法变更及分页逻辑优化,可参考官方《Azure AD Graph客户端库迁移至Microsoft Graph》文档完成细节适配。

内容的提问来源于stack exchange,提问作者Nachiappan R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 21:24:54