迁移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
相关产品推荐
相关产品推荐

