在Azure Function中使用Graph API(SDK5.35)的FindMeetingTimes遇错误求助
解决Azure Function中使用Graph SDK调用FindMeetingTimes的两个问题
问题1:/me request is only valid with delegated authentication flow 错误
- 原因:你当前使用客户端凭证(Client Credentials)认证流,这是应用级权限,没有关联具体用户上下文。而
/me端点需要依托用户的委托权限(如Authorization Code流),因为/me指向"当前登录用户",客户端凭证流不存在该上下文,因此无法使用。 - 解决方案:必须切换到指定具体用户ID的调用方式,即使用
graphClient.Users[userId].FindMeetingTimes,同时确保应用已被授予对应的应用权限。
问题2:Invalid user address 错误
- 原因:
- 请求体类型不匹配:你当前使用的
Microsoft.Graph.Me.FindMeetingTimes.FindMeetingTimesPostRequestBody是专为/me端点设计的,调用/users/{id}端点时,必须使用对应的Microsoft.Graph.Users.Item.FindMeetingTimes.FindMeetingTimesPostRequestBody类型。 - 应用权限不足:客户端凭证流需要授予应用
Calendars.Read.Shared或Calendars.ReadWrite.Shared权限(按需选择),且需管理员同意。 - 参会者邮箱无效:确保参会者邮箱是租户内有效用户邮箱,或外部邮箱已被允许访问。
- 请求体类型不匹配:你当前使用的
- 解决方案:
- 替换请求体类型为
Users端点对应的类型; - 检查并授予正确的应用权限;
- 验证参会者邮箱的有效性。
- 替换请求体类型为
修正后的完整代码
using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Mvc; using Azure.Identity; using Microsoft.Graph; using Microsoft.Graph.Models; namespace Company.Function { public class HttpTrigger0 { private readonly ILogger _logger; public HttpTrigger0(ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger<HttpTrigger0>(); // 修正日志类名称与当前类一致 } [Function("HttpTrigger0")] public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestData req) { _logger.LogInformation("C# HTTP trigger function processed a request."); // 替换为目标用户的实际Object ID var userId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"; var scopes = new[] { "https://graph.microsoft.com/.default" }; var tenantId = Environment.GetEnvironmentVariable("TENANT_ID"); var clientId = Environment.GetEnvironmentVariable("CLIENT_ID"); var clientSecret = Environment.GetEnvironmentVariable("CLIENT_SECRET"); var options = new ClientSecretCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud }; var clientSecretCredential = new ClientSecretCredential( tenantId, clientId, clientSecret, options); var graphClient = new GraphServiceClient(clientSecretCredential, scopes); // 使用Users端点对应的请求体类型 var requestBody = new Microsoft.Graph.Users.Item.FindMeetingTimes.FindMeetingTimesPostRequestBody { Attendees = new List<AttendeeBase> { new AttendeeBase { EmailAddress = new EmailAddress { Name = "User1", Address = "user1@test.onmicrosoft.com", }, }, new AttendeeBase { EmailAddress = new EmailAddress { Name = "User2", Address = "user2@test.onmicrosoft.com", }, }, new AttendeeBase { EmailAddress = new EmailAddress { Name = "User3", Address = "user3@test.onmicrosoft.com", }, }, }, // 可选:添加时间约束,避免因缺少必要参数导致的额外错误 TimeConstraint = new TimeConstraint { Timeslots = new List<TimeSlot> { new TimeSlot { Start = new DateTimeTimeZone { DateTime = DateTime.UtcNow.AddDays(1).ToString("yyyy-MM-ddTHH:mm:ss"), TimeZone = "UTC" }, End = new DateTimeTimeZone { DateTime = DateTime.UtcNow.AddDays(1).AddHours(1).ToString("yyyy-MM-ddTHH:mm:ss"), TimeZone = "UTC" } } } } }; try { var result = await graphClient.Users[userId].FindMeetingTimes.PostAsync(requestBody); return new OkObjectResult(result); } catch (Exception e) { _logger.LogError(e, "调用FindMeetingTimes失败"); return new BadRequestObjectResult(new { Error = e.Message, StackTrace = e.StackTrace }); } } } }
额外注意事项
- 确保Azure AD应用已授予
Calendars.Read.Shared或更高权限,且已获得管理员同意; - 验证
userId是目标用户的正确Object ID(而非用户主体名称); - 若参会者包含外部用户,需确保租户允许外部日历访问。
内容的提问来源于stack exchange,提问作者takaaki
相关产品推荐
相关产品推荐

