.NET 5 Web API如何验证MS Azure AD等外部颁发方的JWT Bearer令牌?
需求可行性确认
你描述的需求完全可实现,.NET 5内置的JWT Bearer认证组件原生支持外部颁发方的令牌验签,无需自身实现令牌颁发逻辑,仅需做少量配置即可完成令牌验签、角色提取和权限校验。
.NET Core 认证与授权核心逻辑说明
先理清两个核心模块的职责,解决你对运行逻辑的困惑:
- 认证(Authentication):仅负责校验请求携带的令牌合法性,完成验签、过期校验、签发方/受众校验后,会把令牌内的所有声明(角色、用户ID、用户名等)解析到
HttpContext.User属性中,该阶段只判断「请求方身份是否合法」,不判断是否有权限访问接口。 - 授权(Authorization):基于认证阶段拿到的声明信息,判断当前请求是否满足接口的访问规则(比如是否属于指定角色),该阶段负责判断「请求方是否有权限访问当前接口」。
正确配置步骤
1. 安装依赖NuGet包
安装版本号匹配.NET 5的以下包:
Microsoft.AspNetCore.Authentication.JwtBearer核心JWT认证组件Swashbuckle.AspNetCoreSwagger相关组件(已安装可忽略)
2. 新增配置项
在appsettings.json中新增Azure AD相关配置:
{ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "你的Azure AD租户ID", "Audience": "你在Azure AD中注册的API的标识,通常为api://<API客户端ID>" } }
你可以先把已获取到的Bearer令牌粘贴到第三方JWT解析工具中查看aud字段的值,确保和此处配置的Audience完全一致。
3. 配置认证与授权服务
修改Startup.cs的ConfigureServices方法:
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); // 注册JWT Bearer认证服务 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = $"{Configuration["AzureAd:Instance"]}{Configuration["AzureAd:TenantId"]}/v2.0"; options.Audience = Configuration["AzureAd:Audience"]; // 配置令牌校验规则 options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, // 指定角色声明的key为Azure AD返回的roles字段 RoleClaimType = "roles" }; }); // 可选:配置自定义授权策略 services.AddAuthorization(options => { options.AddPolicy("AdminAccess", policy => policy.RequireRole("Admin")); }); // 配置Swagger支持Azure AD OAuth2认证 services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "DemoAPI", Version = "v1" }); c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, Flows = new OpenApiOAuthFlows { AuthorizationCode = new OpenApiOAuthFlow { AuthorizationUrl = new Uri($"{Configuration["AzureAd:Instance"]}{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/authorize"), TokenUrl = new Uri($"{Configuration["AzureAd:Instance"]}{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/token"), Scopes = new Dictionary<string, string> { // 替换为你在Azure AD中为API暴露的权限范围 { "api://<API客户端ID>/Access.All", "访问接口的全量权限" } } } } }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }, new []{ "api://<API客户端ID>/Access.All" } } }); }); }
4. 配置中间件管道
修改Startup.cs的Configure方法,严格注意中间件顺序,顺序错误是90%以上认证失效的原因:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "DemoAPI v1"); // 替换为你在Azure AD中注册的前端/客户端应用的客户端ID c.OAuthClientId("<客户端应用ID>"); c.OAuthUsePkce(); }); } app.UseHttpsRedirection(); app.UseRouting(); // 必须先启用认证,再启用授权,顺序不能反 app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
5. 接口权限配置
仅在需要保护的接口上添加[Authorize]特性即可,无需全局配置:
// 公开接口,不需要令牌即可访问 [ApiController] [Route("api/[controller]")] public class PublicController : ControllerBase { [HttpGet] public IActionResult Get() => Ok("公开接口返回内容"); } // 受保护接口,需要携带合法Azure AD令牌才能访问 [Authorize] [ApiController] [Route("api/[controller]")] public class ProtectedController : ControllerBase { [HttpGet("all")] public IActionResult GetAll() => Ok("所有合法用户都可访问"); // 仅Admin角色可访问 [HttpGet("admin")] [Authorize(Roles = "Admin")] public IActionResult GetAdminData() => Ok("仅Admin可访问的内容"); // 使用自定义授权策略 [HttpGet("policy")] [Authorize(Policy = "AdminAccess")] public IActionResult GetPolicyData() => Ok("基于自定义策略校验的内容"); }
常见报错排查
如果携带令牌调用依然报错,优先排查以下问题:
- 确认令牌的
iss(签发方)字段值和配置的Authority完全一致,v1和v2端点的签发方地址不同,不匹配会直接返回401 - 确认令牌的
aud(受众)字段值和配置的Audience完全一致,填错API标识会校验失败 - 确认请求令牌时已经勾选了对应API的权限范围,否则令牌内没有对应scope声明会校验失败
- 确认
UseAuthentication中间件放在UseAuthorization之前,顺序错误会导致认证逻辑不执行
内容的提问来源于stack exchange,提问作者sebascomeau
相关产品推荐
相关产品推荐

