快速入门:保护 ASP.NET Core Web API

在本快速入门中,你将使用 Microsoft.Identity.Web 通过 Microsoft Entra ID 保护 ASP.NET Core Web API。 添加验证持有者令牌并限制对授权调用方的访问权限的身份验证中间件。

如果没有 Azure 订阅,请在开始之前先创建一个免费帐户

先决条件

选项 1:从模板创建(最快)

使用具有内置Microsoft Entra身份验证的 ASP.NET Core 模板为受保护的 API 项目搭建基架。

1.创建项目

运行以下命令,使用单组织身份验证创建新的 Web API 项目,并导航到项目目录:

dotnet new webapi --auth SingleOrg --name MyWebApi
cd MyWebApi

2.配置应用注册

appsettings.json 中的占位符值替换为Microsoft Entra应用注册详细信息:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-api-client-id"
  }
}

3.运行 API

启动应用程序:

dotnet run

您的 API 现已受到保护,位于 https://localhost:5001

完成! 请求现在需要有效的访问令牌。


选项 2:添加到现有 Web API

如果已有 ASP.NET Core Web API,请使用以下步骤添加Microsoft Entra身份验证。

1.安装 NuGet 包

将 Microsoft.Identity.Web NuGet 包添加到项目中:

dotnet add package Microsoft.Identity.Web

2. 在 Program.cs 中配置身份验证

在应用的启动管道中注册身份验证和授权服务。 以下代码配置了 JWT 持有者身份验证,并通过 Microsoft Entra 进行验证:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// Add authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApi(builder.Configuration, "AzureAd");

// Add authorization
builder.Services.AddAuthorization();

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthentication(); //  Add authentication middleware
app.UseAuthorization();

app.MapControllers();

app.Run();

3. 将配置添加到 appsettings.json

在Microsoft Entra中添加包含租户和应用程序详细信息的配置部分。 将 Microsoft.Identity.Web 的日志记录级别设置为 Information,以帮助排查令牌验证问题:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-api-client-id"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.Identity.Web": "Information"
    }
  }
}

4.保护 API 终结点

[Authorize] 属性应用于需要有效访问令牌的控制器或操作。

要求对所有终结点进行身份验证:

以下控制器需要对所有操作的有效访问令牌,并演示如何访问用户声明:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[Authorize] //  Require valid access token
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        // Access user information
        var userId = User.FindFirst("oid")?.Value;
        var userName = User.Identity?.Name;

        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = "Protected data"
        });
    }
}

需要特定范围:

使用 [RequiredScope] 属性对单个操作强制实施细化权限:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web;

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class TodoController : ControllerBase
{
    [HttpGet]
    [RequiredScope("access_as_user")] //  Require specific scope
    public IActionResult GetAll()
    {
        return Ok(new[] { "Todo 1", "Todo 2" });
    }

    [HttpPost]
    [RequiredScope("write")] //  Different scope for write operations
    public IActionResult Create([FromBody] string item)
    {
        return Created("", item);
    }
}

5. 运行和测试

启动应用程序并验证未经身份验证的请求是否被拒绝:

dotnet run

使用 Postman 或 curl 等工具进行测试。 未经身份验证的请求返回 401 Unauthorized

curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" https://localhost:5001/api/weatherforecast

成功! API 现在验证持有者令牌。


应用注册设置

在 API 验证令牌之前,需要Microsoft Entra应用注册。 在 Azure 门户中执行以下步骤。

1.注册 API

  1. 登录到 Azure 门户
  2. 导航到 Microsoft Entra ID>应用注册>新注册
  3. 输入名称(例如“我的 Web API”)
  4. 选择 单租户(这是 API 最常用的选项)
  5. API 不需要重定向 URI
  6. 单击“注册”

2.公开 API 范围

定义客户端应用在调用 API 时可以请求的权限(范围)。

  1. 在 API 应用注册中,转到“公开 API
  2. 单击“添加范围
  3. 接受默认应用程序 ID URI 或对其进行自定义(例如 api://your-api-client-id
  4. 添加范围:
    • 范围名称:access_as_user
    • 谁可以同意: 管理员和用户
    • 管理员同意显示名称: “访问我的 Web API”
    • 管理员同意说明: “允许应用代表已登录用户访问 Web API”
  5. 单击“添加范围

3.记下应用程序 ID

从应用注册概述页复制 应用程序(客户端)ID 。 此值是你的 ClientIdappsettings.json


创建客户端应用注册(用于测试)

若要测试受保护的 API,请注册一个单独的客户端应用程序,用于获取令牌并调用 API。

1.注册客户端应用程序

  1. Microsoft Entra ID>应用注册 中,创建另一个注册
  2. 将其命名(例如,“我的 API 客户端”)
  3. 选择帐户类型
  4. 添加重定向 URI: https://localhost:7000/signin-oidc (如果是 Web 应用)
  5. 单击“注册”

2. 授予 API 权限

授予客户端应用程序根据您定义的作用域调用 API 的权限。

  1. 在客户端应用注册中,转到 API 权限
  2. 单击“ 添加权限>我的 API”
  3. 选择你的 API 注册信息
  4. 检查access_as_user范围
  5. 单击“添加权限
  6. 单击“ 授予管理员同意 ”(如果需要)

3.创建客户端密码(适用于机密客户端)

如果客户端应用在服务器上(而不是浏览器或移动设备)上运行,请创建用于身份验证的客户端密码。

  1. 转到 证书和机密
  2. 单击“新建客户端密码
  3. 添加说明和过期时间
  4. 单击“ 添加”
  5. 立即复制机密值 - 无法再次看到它

测试受保护的 API

通过发送经过身份验证的请求验证 API 是否正确验证令牌。

使用 Postman

在 Postman 中设置 OAuth 2.0 身份验证,以获取令牌并调用 API。

  1. 在 Postman 中创建新请求
  2. 设置 OAuth 2.0 身份验证:
    • 授予类型: 授权代码(适用于用户上下文)或客户端凭据(适用于应用上下文)
    • 身份验证 URL:https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize
    • 访问令牌 URL:https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
    • 客户端 ID: 客户端应用的客户端 ID
    • 客户端密码: 客户端应用的机密
    • 范围:api://your-api-client-id/access_as_user
  3. 单击“获取新访问令牌
  4. 使用令牌调用您的 API

使用代码 (C# 示例)

以下示例使用 MSAL.NET,通过客户端凭据流获取令牌,并调用受保护的 API:

// In a console app or client application
using Microsoft.Identity.Client;

var app = ConfidentialClientApplicationBuilder
    .Create("client-app-id")
    .WithClientSecret("client-secret")
    .WithAuthority("https://login.microsoftonline.com/{tenant-id}")
    .Build();

var result = await app.AcquireTokenForClient(
    new[] { "api://your-api-client-id/.default" }
).ExecuteAsync();

var accessToken = result.AccessToken;

// Use the token to call your API
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", accessToken);

var response = await client.GetAsync("https://localhost:5001/api/weatherforecast");

常见配置选项

Microsoft。Identity.Web 支持不同方案的多种配置模式。

在配置中需要指定特定范围

缺省使用[RequiredScope]属性,您可以在appsettings.json中全局配置所需范围。

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-api-client-id",
    "Scopes": "access_as_user"
  }
}

接受来自多个租户的令牌

若要接受来自任何Microsoft Entra租户的令牌,请将 TenantId 设置为 common

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "common",
    "ClientId": "your-api-client-id"
  }
}

配置令牌验证

如果 API 调用下游 API(例如Microsoft Graph),请启用令牌获取并配置令牌缓存:

builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi() // If your API calls other APIs
    .AddInMemoryTokenCaches();

后续步骤

拥有受保护的 API 后,请浏览以下主题:

故障排除

401 未授权

问题: 即使使用令牌,API 也会返回 401。

可能的原因:

  • 令牌受众(aud 声明)与您的 API ClientId 不匹配
  • 令牌已过期
  • 令牌适用于错误的租户
  • 缺少所需的范围

解决 方案:jwt.ms 解码令牌并验证声明。 有关详细故障排除 ,请参阅日志记录和诊断

AADSTS50013:签名无效

问题: 令牌签名验证失败。

解决方案: 确保你的 TenantIdClientId 正确。 令牌必须由预期颁发机构颁发。 启用详细日志记录以查看验证错误。

令牌中未找到的范围

问题:[RequiredScope] 属性失败。

Solution:

  1. 验证客户端应用是否有权访问范围
  2. 确保授予管理员同意(如果需要)
  3. 有关完整的范围验证模式,请参阅授权指南
  4. 请检查在获取令牌时是否请求了作用域(例如 api://your-api/.default 或特定作用域)

请参阅详细信息:Web API 故障排除指南