使用 Azure AD B2C 在你自己的 Web API 中启用身份验证

若要授权访问 Web API,可以仅处理包含 Azure Active Directory B2C (Azure AD B2C) 颁发的有效访问令牌的请求。 本文介绍了如何启用对 Web API 的 Azure AD B2C 授权。 完成本文中的步骤后,只有获取了有效访问令牌的用户才有权调用你的 Web API 终结点。

先决条件

在开始操作之前,请阅读以下文章之一,其中介绍了如何为调用 Web API 的应用配置身份验证。 然后,按照本文中的步骤将示例 Web API 替换为你自己的 Web API。

概述

基于令牌的身份验证确保对 Web API 的请求包含有效的访问令牌。

该应用完成以下步骤:

  1. 通过 Azure AD B2C 对用户进行身份验证。

  2. 获取一个具有对 Web API 终结点的必需权限(作用域)的访问令牌。

  3. 使用以下格式,在 HTTP 请求的身份验证标头中将该访问令牌作为持有者令牌进行传递:

    Authorization: Bearer <access token>
    

该 Web API 完成以下步骤:

  1. 从 HTTP 请求中的授权标头读取持有者令牌。

  2. 验证该令牌。

  3. 验证令牌中的权限(作用域)。

  4. 读取在令牌中编码的声明(可选)。

  5. 响应 HTTP 请求。

应用注册概述

要使应用能够通过 Azure AD B2C 登录并调用 Web API,需要在 Azure AD B2C 目录中注册两个应用程序。

  • Web 应用程序、移动应用程序或 SPA 应用程序注册使你的应用可以通过 Azure AD B2C 登录。 应用注册过程会生成一个应用程序 ID(也称为客户端 ID),用于唯一标识你的应用程序(例如,应用 ID:1)。

  • 注册 Web API 后,你的应用就能够调用受保护的 Web API。 注册将公开 Web API 权限(范围)。 应用注册过程会生成一个应用程序 ID,用于唯一标识你的 Web API(例如,应用 ID:2)。 向应用(应用 ID:1)授予对 Web API 范围(应用 ID:2)的权限。

下图描绘了应用程序注册和应用程序体系结构:

Diagram of the application registrations and the application architecture for an app with web API.

准备开发环境

在接下来的步骤中,创建一个新的 Web API 项目。 选择编程语言:ASP.NET Core 或 Node.js。 确保有一台运行以下任一软件的计算机:

步骤 1:创建受保护的 Web API

创建一个新的 Web API 项目。 首先,选择要使用的编程语言:ASP.NET Core 或 Node.js。

使用 dotnet new 命令。 dotnet new 命令创建一个名为 TodoList 的新文件夹,其中包含 Web API 项目资产。 打开目录,然后打开 Visual Studio Code

dotnet new webapi -o TodoList
cd TodoList
code . 

系统提示你“将所需资产添加到项目”时,请选择“是”。

步骤 2:安装依赖项

在你的 Web API 项目中添加身份验证库。 身份验证库将分析 HTTP 身份验证头,验证令牌,并提取声明。 有关详细信息,请查看该库的文档。

若要添加身份验证库,请运行以下命令安装相应的包:

dotnet add package Microsoft.Identity.Web

步骤 3:启动身份验证库

添加所需的代码来启动身份验证库。

打开 Startup.cs,然后在类的开头添加以下 using 声明:

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

找到 ConfigureServices(IServiceCollection services) 函数。 然后在 services.AddControllers(); 代码行的前面添加以下代码片段:

public void ConfigureServices(IServiceCollection services)
{
    // Adds Microsoft Identity platform (Azure AD B2C) support to protect this Api
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApi(options =>
    {
        Configuration.Bind("AzureAdB2C", options);

        options.TokenValidationParameters.NameClaimType = "name";
    },
    options => { Configuration.Bind("AzureAdB2C", options); });
    // End of the Microsoft Identity platform block    

    services.AddControllers();
}

找到 Configure 函数。 然后,紧接在 app.UseRouting(); 代码行的后面添加以下代码片段:

app.UseAuthentication();

更改后,你的代码应如以下代码片段所示:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseHttpsRedirection();

    app.UseRouting();
    
    // Add the following line 
    app.UseAuthentication();
    // End of the block you add
    
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

步骤 4:添加终结点

向 Web API 中添加两个终结点:

  • 匿名的 /public 终结点。 此终结点返回当前日期和时间。 使用它通过匿名调用来调试 Web API。
  • 受保护的 /hello 终结点。 此终结点返回访问令牌中的 name 声明值。

若要添加匿名终结点,请执行以下操作:

/Controllers 文件夹下,添加 PublicController.cs 文件,然后将其添加到以下代码片段:

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace TodoList.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class PublicController : ControllerBase
    {
        private readonly ILogger<PublicController> _logger;

        public PublicController(ILogger<PublicController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public ActionResult Get()
        {
            return Ok( new {date = DateTime.UtcNow.ToString()});
        }
    }
}

若要添加受保护的终结点,请执行以下操作:

/Controllers 文件夹下,添加 HelloController.cs 文件,然后将其添加到以下代码:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Web.Resource;

namespace TodoList.Controllers
{
    [Authorize]
    [RequiredScope("tasks.read")]
    [ApiController]
    [Route("[controller]")]
    public class HelloController : ControllerBase
    {

        private readonly ILogger<HelloController> _logger;
        private readonly IHttpContextAccessor _contextAccessor;

        public HelloController(ILogger<HelloController> logger, IHttpContextAccessor contextAccessor)
        {
            _logger = logger;
            _contextAccessor = contextAccessor;
        }

        [HttpGet]
        public ActionResult Get()
        {
            return Ok( new { name = User.Identity.Name});
        }
    }
}

HelloController 控制器由 AuthorizeAttribute 修饰,这将仅向已通过身份验证的用户授予访问权限。

该控制器还使用 [RequiredScope("tasks.read")] 进行修饰。 RequiredScopeAttribute 验证 Web API 是否是使用正确的范围 tasks.read 调用的。

步骤 5:配置 Web 服务器

在开发环境中,将 Web API 设置为侦听传入的 HTTP 或 HTTPS 请求端口号。 本示例使用 HTTP 端口 6000 和 HTTPS 端口 6001。 Web API 的基 URI 将为 http://localhost:6000(针对 HTTP)和 https://localhost:6001(针对 HTTPS)。

将以下 JSON 代码片段添加到 appsettings.json 文件。

"Kestrel": {
    "EndPoints": {
      "Http": {
        "Url": "http://localhost:6000"
      },
      "Https": {
         "Url": "https://localhost:6001"   
        }
    }
  }

步骤 6:配置 Web API

向配置文件中添加配置。 该文件包含有关 Azure AD B2C 标识提供者的信息。 Web API 应用使用此信息来验证访问令牌,该访问令牌由 Web 应用当作持有者令牌传递。

在项目根文件夹下,打开 appsettings.json 文件,然后添加以下设置:

{
  "AzureAdB2C": {
    "Instance": "https://contoso.b2clogin.cn",
    "Domain": "contoso.partner.onmschina.cn",
    "ClientId": "<web-api-app-application-id>",
    "SignedOutCallbackPath": "/signout/<your-sign-up-in-policy>",
    "SignUpSignInPolicyId": "<your-sign-up-in-policy>"
  },
  // More settings here
}

在 appsettings.json 文件中,更新以下属性:

部分 密钥
AzureAdB2C 实例 Azure AD B2C 租户名称的第一部分(例如 https://contoso.b2clogin.cn)。
AzureAdB2C Azure AD B2C 租户的完整租户名称(例如 contoso.partner.onmschina.cn)。
AzureAdB2C ClientId Web API 应用程序 ID。 在上面的示意图中,它是标有“应用 ID: 2”的应用程序。 若要了解如何获取 Web API 应用程序注册 ID,请参阅先决条件
AzureAdB2C SignUpSignInPolicyId 用户流或自定义策略。 若要了解如何获取用户流或策略,请参阅先决条件

步骤 7:运行并测试 Web API

最后,使用你的 Azure AD B2C 环境设置运行该 Web API。

在命令 shell 中,通过运行以下命令来启动 Web 应用:

 dotnet run

你应会看到以下输出,这意味着你的应用已启动并正在运行,并已做好接收请求的准备。

Now listening on: http://localhost:6000

若要停止该程序,请在命令 shell 中选择“Ctrl+C”。 可以使用 node app.js 命令重新运行应用。

提示

若要运行 dotnet run 命令,还可以使用 Visual Studio Code 调试程序。 Visual Studio Code 的内置调试程序有助于加速编辑、编译和调试循环。

打开浏览器并转到 http://localhost:6000/public。 在浏览器窗口中,应会看到显示了以下文本以及当前日期和时间。

步骤 8:从应用中调用 Web API

尝试在不使用访问令牌的情况下调用受保护的 Web API 终结点。 打开浏览器并转到 http://localhost:6000/hello。 API 将返回“未授权”HTTP 错误消息,此时可以确认该 Web API 受持有者令牌的保护。

继续配置应用以调用 Web API。 有关指导,请参阅先决条件部分。

后续步骤

获取 GitHub 中的完整示例: