You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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.AspNetCore Swagger相关组件(已安装可忽略)

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 17:54:03