在.NET Core 6/7/8中集成Microsoft Graph API 5.x.x的授权与调用问询
问题描述
我希望在.NET Core 6/7/8 Web API中使用Microsoft Graph API 5.x.x,同时支持委托权限与应用权限。需要提供带[Authorize]特性的控制器、Program.cs、appsettings.json示例,以及Microsoft Azure AD的应用注册流程;还要包含通过委托/应用令牌调用获取当前用户(Me)的示例。我多次尝试后在Program.cs的授权依赖注入(DI)集成环节受阻,以下是我使用的NuGet包、控制器、Program.cs及appsettings.json的完整代码:
现有代码
我使用的NuGet包
<ItemGroup> <PackageReference Include="Microsoft.Graph" Version="5.41.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.10" NoWarn="NU1605" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.10" NoWarn="NU1605" /> <PackageReference Include="Microsoft.Identity.Client" Version="4.55.0" /> <PackageReference Include="Microsoft.Identity.Web" Version="2.13.3" /> <PackageReference Include="Microsoft.Identity.Web.GraphServiceClient" Version="2.13.3" /> <PackageReference Include="Microsoft.Identity.Web.UI" Version="2.13.3" /> </ItemGroup>
我的控制器代码
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Diagnostics; using Microsoft.Kiota.Abstractions; using Microsoft.Identity.Client; using Microsoft.Identity.Web; using Microsoft.Graph; namespace WebApp.Controllers { [Route("api/v1.0/user")] [ApiController] [Authorize] public class MasterController : Controller { private readonly ILogger<MasterController> _logger; private readonly GraphServiceClient _graphServiceClient; public MasterController(GraphServiceClient graphServiceClient, ILogger<MasterController> logger) { _logger = logger; _graphServiceClient = graphServiceClient; } [HttpGet("GetMyProfile")] public async Task<IActionResult> GetMyProfile() { try { var user = await _graphServiceClient.Me.GetAsync(); return this.Ok(user); } catch (Exception ex) { _logger.LogError(ex, "Error getting user profile"); return this.Problem(ex.Message); } } } }
我的Program.cs代码
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.Extensions.Configuration; using Microsoft.Graph; using Microsoft.Identity.Client; using Microsoft.Identity.Web; using Microsoft.Identity.Web.UI; using Microsoft.Kiota.Abstractions.Authentication; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi() .AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph")) .AddInMemoryTokenCaches(); builder.Services.AddAuthorization(); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run(); var scopeRequiredByApi = app.Configuration["AzureAd:Scopes"] ?? "";
我的appsettings.json配置
{ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "Domain": "XXXXX.onmicrosoft.com", "TenantId": "XXXXXXXXXXXXXXXXXXXX", "ClientId": "XXXXXXXXXXXXXXXXXXXX", "CallbackPath": "/signin-oidc", "Scopes": "access_as_user", "ClientSecret": "XXXXXXXXXXXXXXXX", "ClientCertificates": [] }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "MicrosoftGraph": { "BaseUrl": "https://graph.microsoft.com/v1.0", "Scopes": "user.read" } }
解决方案:支持委托与应用权限的集成配置
一、修正后的Program.cs配置
核心调整:移除Web UI相关依赖(Web API无需UI组件),分别注册委托/应用权限的GraphServiceClient实例,配置区分两种权限的授权策略。
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Configuration; using Microsoft.Graph; using Microsoft.Identity.Web; using Microsoft.Identity.Web.Resource; var builder = WebApplication.CreateBuilder(args); // 1. 配置身份验证,同时支持委托和应用权限的Graph调用 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi() // 注册委托权限用的Graph客户端(基于用户令牌) .AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph:Delegated")) // 注册应用权限用的Graph客户端(基于应用令牌) .AddMicrosoftGraphAppOnly(builder.Configuration.GetSection("MicrosoftGraph:Application")) .AddInMemoryTokenCaches(); // 2. 配置授权策略,区分委托和应用权限访问 builder.Services.AddAuthorization(options => { options.AddPolicy("DelegatedAccess", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("scp", builder.Configuration["AzureAd:DelegatedScopes"]?.Split(',') ?? Array.Empty<string>()); }); options.AddPolicy("ApplicationAccess", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("roles", builder.Configuration["AzureAd:ApplicationRoles"]?.Split(',') ?? Array.Empty<string>()); }); }); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
二、更新后的appsettings.json配置
新增区分委托/应用权限的Graph配置,明确对应权限范围:
{ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "Domain": "XXXXX.onmicrosoft.com", "TenantId": "XXXXXXXXXXXXXXXXXXXX", "ClientId": "XXXXXXXXXXXXXXXXXXXX", "ClientSecret": "XXXXXXXXXXXXXXXX", "DelegatedScopes": "user.read", "ApplicationRoles": "User.Read.All" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "MicrosoftGraph": { "Delegated": { "BaseUrl": "https://graph.microsoft.com/v1.0", "Scopes": "user.read" }, "Application": { "BaseUrl": "https://graph.microsoft.com/v1.0", "Scopes": "https://graph.microsoft.com/.default" } } }
三、支持两种权限的控制器示例
通过构造函数注入两种GraphServiceClient实例,用授权策略限制接口访问范围:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Graph; using Microsoft.Identity.Web; namespace WebApp.Controllers { [Route("api/v1.0/users")] [ApiController] public class UserController : ControllerBase { private readonly ILogger<UserController> _logger; private readonly GraphServiceClient _delegatedGraphClient; private readonly GraphServiceClient _applicationGraphClient; // 注入委托权限和应用权限的Graph客户端 public UserController( ILogger<UserController> logger, GraphServiceClient delegatedGraphClient, [FromKeyedServices("MicrosoftGraphAppOnly")] GraphServiceClient applicationGraphClient) { _logger = logger; _delegatedGraphClient = delegatedGraphClient; _applicationGraphClient = applicationGraphClient; } /// <summary> /// 委托权限调用:获取当前用户信息(仅用户上下文可用Me接口) /// </summary> [HttpGet("me")] [Authorize(Policy = "DelegatedAccess")] public async Task<IActionResult> GetCurrentUser() { try { var user = await _delegatedGraphClient.Me.GetAsync(); return Ok(user); } catch (Exception ex) { _logger.LogError(ex, "获取当前用户信息失败"); return Problem(ex.Message); } } /// <summary> /// 应用权限调用:获取指定用户信息(应用权限无法使用Me接口) /// </summary> [HttpGet("{userId}")] [Authorize(Policy = "ApplicationAccess")] public async Task<IActionResult> GetUserById(string userId) { try { var user = await _applicationGraphClient.Users[userId].GetAsync(); return Ok(user); } catch (Exception ex) { _logger.LogError(ex, "获取用户信息失败"); return Problem(ex.Message); } } } }
四、Azure AD应用注册流程
1. 创建应用注册
- 登录Azure门户,进入Azure Active Directory → 应用注册 → 新注册
- 填写应用名称,选择账户类型(如“仅此组织目录中的账户”),重定向URI留空,点击注册
2. 配置API权限
委托权限(用户上下文调用)
- 进入API权限 → 添加权限 → Microsoft Graph → 委托权限
- 搜索并添加
User.Read权限,点击添加权限 - 点击授予管理员同意(需租户管理员权限)
应用权限(后台服务调用)
- 再次点击添加权限 → Microsoft Graph → 应用权限
- 搜索并添加
User.Read.All权限,点击添加权限 - 点击授予管理员同意(需租户管理员权限)
3. 生成客户端密钥
- 进入证书和密码 → 客户端密码 → 新客户端密码
- 填写描述和过期时间,点击添加,保存生成的密码值(仅显示一次)
4. 自定义范围(可选)
- 进入公开API → 添加范围,设置范围名称(如
access_as_user),保存后记录完整范围URL
五、调用示例
委托权限调用(用户令牌)
使用OAuth2授权码流获取用户令牌,请求头携带:
Authorization: Bearer {用户访问令牌}
令牌需包含User.Read范围。
应用权限调用(应用令牌)
使用客户端凭证流获取应用令牌,请求头携带:
Authorization: Bearer {应用访问令牌}
令牌需包含User.Read.All角色。
内容的提问来源于stack exchange,提问作者Ayon Maji
相关产品推荐
相关产品推荐

