调用Microsoft Graph API获取访问令牌失败的技术咨询
问题描述
我尝试调用Microsoft Graph API读取用户邮件,但调用服务时遇到问题。目前已完成用户认证,但无法获取访问Graph API的令牌。我理解的流程为:
- 重定向用户至Microsoft Identity Platform进行认证
- 授权时需提供scopes、tenantId、clientId、clientSecret和授权码
- 访问Graph API
控制器代码(Microsoft登录)
public IActionResult MicrosoftLogin() { // Redirect user to Microsoft Identity Platform for authentication return Challenge(new AuthenticationProperties { RedirectUri = "/Home/MicrosoftCallback" }, OpenIdConnectDefaults.AuthenticationScheme); }
回调代码
public async Task<IActionResult> MicrosoftCallback() { try { var scopes = new[] { "User.Read" }; // Multi-tenant apps can use "common", // single-tenant apps must use the tenant ID from the Azure portal var tenantId = "common"; // Values from app registration var clientId = "YOUR_CLIENT_ID"; var clientSecret = "YOUR_CLIENT_SECRET"; var authorizationCode = "AUTH_CODE_FROM_REDIRECT"; // using Azure.Identity; var options = new AuthorizationCodeCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud, }; var authCodeCredential = new AuthorizationCodeCredential( tenantId, clientId, clientSecret, authorizationCode, options); var graphClient = new GraphServiceClient(authCodeCredential, scopes); var user = await graphClient.Users.GetAsync(); var outlookmail = await graphClient.Me.Messages.GetAsync(); ViewData["user"] = user; ViewData["mail"] = outlookmail; return View("MicrosoftHome"); } catch (ServiceException ex) { Console.WriteLine("Error" + ex); return View(); } }
Program.cs代码
string[] initialScopes = configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' '); services .AddAuthentication(options => { //options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; //options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme; options.DefaultScheme = "AppCookie"; options.DefaultChallengeScheme = "MyAzureAdScheme"; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie("AppCookie") .AddGoogle(GoogleDefaults.AuthenticationScheme, googleOptions => { googleOptions.ClientId = builder.Configuration["Authentication:Google:ClientId"]; googleOptions.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"]; googleOptions.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url"); // Add the required scope for GMail API access googleOptions.Scope.Add("https://www.googleapis.com/auth/gmail.readonly"); googleOptions.SaveTokens = true; }) .AddMicrosoftIdentityWebApp(configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(configuration.GetSection("DownstreamApi")) .AddInMemoryTokenCaches();
疑问
回调代码参考了Authorization Code Provider相关文档,不确定是否需要将scopes、tenantId、clientId、clientSecret替换为AAD注册应用的信息;若需要,请问如何获取授权码?
解决方案
1. 必须替换的配置项
是的,必须将代码中的占位符替换为AAD应用注册的真实信息:
- scopes:当前仅配置了
User.Read,不足以访问邮件,需添加Mail.Read,改为new[] { "User.Read", "Mail.Read" } - tenantId:多租户应用用
common没问题,单租户应用需替换为Azure门户中你的租户ID - clientId:替换为AAD应用注册里的「应用程序(客户端)ID」
- clientSecret:替换为AAD应用注册中生成的「客户端密码」(生成后无法再次查看,需妥善保存)
2. 授权码的正确获取方式
你当前手动写死AUTH_CODE_FROM_REDIRECT是错误的,授权码是用户完成认证后,Microsoft Identity Platform自动返回给回调地址的。结合你已使用Microsoft.Identity.Web库,推荐两种更简便的处理方式:
方式一:利用Microsoft.Identity.Web内置能力(推荐)
你已经在Program.cs中配置了AddMicrosoftGraph,可以直接在控制器中注入GraphServiceClient,无需手动处理令牌流程:
private readonly GraphServiceClient _graphServiceClient; public HomeController(GraphServiceClient graphServiceClient) { _graphServiceClient = graphServiceClient; } public async Task<IActionResult> MicrosoftCallback() { try { var user = await _graphServiceClient.Me.GetAsync(); var outlookmail = await _graphServiceClient.Me.Messages.GetAsync(); ViewData["user"] = user; ViewData["mail"] = outlookmail; return View("MicrosoftHome"); } catch (ServiceException ex) { Console.WriteLine("Error" + ex); return View(); } }
这种方式下,Microsoft.Identity.Web会自动处理令牌的获取、缓存和刷新,无需手动干预。
方式二:手动提取授权码(仅特殊场景使用)
如果一定要手动获取授权码,可从回调请求的HttpContext中提取:
var authorizationCode = await HttpContext.GetTokenAsync("code");
注意:授权码只能一次性使用,且需确保OpenIdConnect配置开启了令牌保存。
3. 额外配置检查
- 确保AAD应用注册中已添加
Mail.Read的委托权限,并完成管理员同意(租户内应用需此步骤) - 检查配置文件中的
DownstreamApi:Scopes,确保包含Mail.Read,例如:"DownstreamApi:Scopes": "User.Read Mail.Read" - Program.cs中重复设置了
DefaultChallengeScheme,建议删除冗余行,保留options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;即可
内容的提问来源于stack exchange,提问作者Wu Bang Zheng
相关产品推荐
相关产品推荐

