你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 Azure AD B2C 在 Web 应用中启用验证选项

本文介绍如何启用、自定义和增强 Web 应用程序的 Azure Active Directory B2C (Azure AD B2C) 身份验证体验。

在开始之前,请务必先熟悉以下文章:

使用自定义域

通过使用自定义域,可以完全标记身份验证 URL。 从用户的角度来看,用户在身份验证过程中仍留在你的域中,而不是重定向到 Azure AD B2C b2clogin.com 域名。

若要删除对 URL 中“b2c”的所有引用,还可以将身份验证请求 URL 中的 B2C 租户名称 (contoso.onmicrosoft.com) 替换为你的租户 ID GUID。 例如,可以将 https://fabrikamb2c.b2clogin.com/contoso.onmicrosoft.com/ 更改为 https://account.contosobank.co.uk/<tenant ID GUID>/

若要在身份验证 URL 中使用自定义域和租户 ID,请按照启用自定义域中的指南进行操作。 在项目根文件夹下,打开 appsettings.json 文件。 此文件包含有关 Azure AD B2C 标识提供者的信息。

在 appsettings.json 文件中,执行以下操作:

  • Instance 条目更新为你的自定义域。
  • Domain 条目更新为你的租户 ID。 有关详细信息,请参阅使用租户 ID

以下 JSON 显示了更改前的应用设置:

"AzureAdB2C": {
  "Instance": "https://contoso.b2clogin.com",
  "Domain": "tenant-name.onmicrosoft.com",
  ...
}

以下 JSON 显示了更改后的应用设置:

"AzureAdB2C": {
  "Instance": "https://login.contoso.com",
  "Domain": "00000000-0000-0000-0000-000000000000",
  ...
}

支持高级方案

Microsoft 标识平台 API 中的 AddMicrosoftIdentityWebAppAuthentication 方法允许开发人员为高级身份验证方案添加代码或订阅 OpenIdConnect 事件。 例如,你可以订阅 OnRedirectToIdentityProvider,它可用于自定义应用发送到 Azure AD B2C 的身份验证请求。

若要支持高级方案,请打开 Startup.cs 文件,然后在 ConfigureServices 函数中,将 AddMicrosoftIdentityWebAppAuthentication 替换为以下代码片段:

// Configuration to sign-in users with Azure AD B2C

//services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C");

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(options =>
{
    Configuration.Bind("AzureAdB2C", options);
    options.Events ??= new OpenIdConnectEvents();
    options.Events.OnRedirectToIdentityProvider += OnRedirectToIdentityProviderFunc;
});

前面的代码添加了 OnRedirectToIdentityProvider 事件以及对 OnRedirectToIdentityProviderFunc 方法的引用。 将以下代码片段添加到 Startup.cs 类。

private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
{
    // Custom code here
    
    // Don't remove this line
    await Task.CompletedTask.ConfigureAwait(false);
}

可以使用上下文参数在控制器和 OnRedirectToIdentityProvider 函数之间传递参数。

预填充登录名

在登录用户旅程中,你的应用可能会针对特定用户。 当应用针对用户时,它可以在授权请求中使用用户登录名指定 login_hint 查询参数。 Azure AD B2C 自动填充登录名,用户只需要提供密码。

若要预填充登录名,请执行下列操作:

  1. 如果使用的是自定义策略,请按照设置直接登录中的说明添加所需的输入声明。

  2. 完成支持高级方案过程。

  3. 将以下代码行添加到 OnRedirectToIdentityProvider 函数:

    private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
    {
      context.ProtocolMessage.LoginHint = "emily@contoso.com";
    
      // More code
      await Task.CompletedTask.ConfigureAwait(false);
    }
    

预先选择标识提供程序

如果已将应用程序的登录旅程配置为包括社交帐户(如 Facebook、LinkedIn 或 Google),则可以指定 domain_hint 参数。 此查询参数向 Azure AD B2C 提供有关应该用于登录的社交标识提供者的提示。 例如,如果应用程序指定 domain_hint=facebook.com,登录流会直接转到 Facebook 登录页。

要将用户重定向到外部标识提供程序,请执行以下操作:

  1. 检查外部标识提供者的域名。 有关详细信息,请参阅将登录重定向到社交服务提供商

  2. 完成支持高级方案过程。

  3. OnRedirectToIdentityProviderFunc 函数中,将以下代码行添加到 OnRedirectToIdentityProvider 函数:

    private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
    {
      context.ProtocolMessage.DomainHint = "facebook.com";
    
      // More code
      await Task.CompletedTask.ConfigureAwait(false);
    }
    

指定 UI 语言

可使用 Azure AD B2C 中的语言自定义让用户流适应各种不同的语言,从而满足客户需求。 有关详细信息,请参阅语言自定义

要设置首选语言,请执行下列操作:

  1. 配置语言自定义

  2. 完成支持高级方案过程。

  3. 将以下代码行添加到 OnRedirectToIdentityProvider 函数:

    private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
    {
      context.ProtocolMessage.UiLocales = "es";
    
      // More code
      await Task.CompletedTask.ConfigureAwait(false);
    }
    

传递自定义查询字符串参数

借助自定义策略,可以传递自定义查询字符串参数。 例如,当你需要动态更改页面内容时。

若要传递自定义查询字符串参数,请执行以下操作:

  1. 配置 ContentDefinitionParameters 元素。

  2. 完成支持高级方案过程。

  3. 将以下代码行添加到 OnRedirectToIdentityProvider 函数:

    private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
    {
      context.ProtocolMessage.Parameters.Add("campaignId", "123");
    
      // More code
      await Task.CompletedTask.ConfigureAwait(false);
    }
    

传递 ID 令牌提示

信赖方应用可随附 OAuth2 授权请求发送入站 JSON Web 令牌 (JWT)。 入站令牌是有关用户或授权请求的提示。 Azure AD B2C 会验证令牌,然后提取声明。

要在身份验证请求中包含 ID 令牌提示,请执行以下操作:

  1. 完成支持高级方案过程。

  2. 在自定义策略中,定义 ID 令牌提示技术配置文件

  3. 将以下代码行添加到 OnRedirectToIdentityProvider 函数:

    private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
    {
      // The idTokenHint variable holds your ID token 
      context.ProtocolMessage.IdTokenHint = idTokenHint
    
      // More code
      await Task.CompletedTask.ConfigureAwait(false);
    }
    

帐户控制器

如果想自定义登录、注册或注销操作,建议创建自己的控制器 。 拥有自己的控制器后,就可以在控制器和身份验证库之间传递参数。 AccountControllerMicrosoft.Identity.Web.UI NuGet 包的一部分,用于处理登录和注销操作。 你可以在 Microsoft 标识 Web 库中找到它的实现。

添加帐户控制器

在 Visual Studio 项目中,右键单击“Controllers”文件夹,然后添加一个新的控制器。 选择“MVC - 空控制器”,然后提供名称“MyAccountController.cs” 。

以下代码片段使用 SignIn 操作演示了自定义 MyAccountController

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;


namespace mywebapp.Controllers
{
    [AllowAnonymous]
    [Area("MicrosoftIdentity")]
    [Route("[area]/[controller]/[action]")]
    public class MyAccountController : Controller
    {

        [HttpGet("{scheme?}")]
        public IActionResult SignIn([FromRoute] string scheme)
        {
            scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
            var redirectUrl = Url.Content("~/");
            var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
            return Challenge(properties, scheme);
        }

    }
}

在 _LoginPartial.cshtml 视图中,将登录链接更改为你的控制器。

<form method="get" asp-area="MicrosoftIdentity" asp-controller="MyAccount" asp-action="SignIn">

传递 Azure AD B2C 策略 ID

以下代码片段使用 SignIn 和 SignUp 操作演示了自定义 MyAccountController 。 该操作将名为 policy 的参数传递到身份验证库。 这使你能够为特定操作提供正确的 Azure AD B2C 策略 ID。

public IActionResult SignIn([FromRoute] string scheme)
{
    scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
    var redirectUrl = Url.Content("~/");
    var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
    properties.Items["policy"] = "B2C_1_SignIn";
    return Challenge(properties, scheme);
}

public IActionResult SignUp([FromRoute] string scheme)
{
    scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
    var redirectUrl = Url.Content("~/");
    var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
    properties.Items["policy"] = "B2C_1_SignUp";
    return Challenge(properties, scheme);
}

在 _LoginPartial.cshtml 视图中,将任何其他身份验证链接(例如注册或编辑个人资料)的 asp-controller 值更改为 MyAccountController

传递自定义参数

以下代码片段使用 SignIn 操作演示了自定义 MyAccountController。 该操作将名为 campaign_id 的参数传递到身份验证库。

public IActionResult SignIn([FromRoute] string scheme)
{
    scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
    var redirectUrl = Url.Content("~/");
    var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
    properties.Items["policy"] = "B2C_1_SignIn";
    properties.Items["campaign_id"] = "1234";
    return Challenge(properties, scheme);
}

完成“支持高级方案”过程,然后在 OnRedirectToIdentityProvider 方法中读取自定义参数:

private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
{
    // Read the custom parameter
    var campaign_id = context.Properties.Items.FirstOrDefault(x => x.Key == "campaign_id").Value;

    // Add your custom code here
    if (campaign_id != null)
    {
        // Send parameter to authentication request
        context.ProtocolMessage.SetParameter("campaign_id", campaign_id);
    }
    
    await Task.CompletedTask.ConfigureAwait(false);
}

保护注销重定向

注销后,用户将重定向到 post_logout_redirect_uri 参数中指定的 URI,而不管为应用程序指定的回复 URL 为何。 但是,如果传递了有效的 id_token_hint 并启用了id_token_hint,则在执行重定向之前,Azure AD B2C 将验证 post_logout_redirect_uri 的值是否与应用程序的某个已配置重定向 URI 相匹配。 如果没有为应用程序配置匹配的回复 URL,则会显示一条错误消息,而用户不会重定向。

若要在应用程序中支持安全的注销重定向,请首先按照帐户控制器支持高级方案部分中的步骤进行操作。 然后按照以下步骤进行操作:

  1. MyAccountController.cs 控制器中,使用以下代码段添加 SignOut 操作:

    [HttpGet("{scheme?}")]
    public async Task<IActionResult> SignOutAsync([FromRoute] string scheme)
    {
        scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
    
        //obtain the id_token
        var idToken = await HttpContext.GetTokenAsync("id_token");
        //send the id_token value to the authentication middleware
        properties.Items["id_token_hint"] = idToken;            
    
        return SignOut(properties,CookieAuthenticationDefaults.AuthenticationScheme,scheme);
    }
    
  2. 在 Startup.cs 类中,解析 id_token_hint 值并将该值附加到身份验证请求。 以下代码片段演示如何将 id_token_hint 值传递给身份验证请求:

    private async Task OnRedirectToIdentityProviderForSignOutFunc(RedirectContext context)
    {
        var id_token_hint = context.Properties.Items.FirstOrDefault(x => x.Key == "id_token_hint").Value;
        if (id_token_hint != null)
        {
            // Send parameter to authentication request
            context.ProtocolMessage.SetParameter("id_token_hint", id_token_hint);
        }
    
        await Task.CompletedTask.ConfigureAwait(false);
    }
    
  3. ConfigureServices 函数中,为控制器添加 SaveTokens 选项可以访问 id_token 值:

    services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(options =>
        {
            Configuration.Bind("AzureAdB2C", options);
            options.Events ??= new OpenIdConnectEvents();        
            options.Events.OnRedirectToIdentityProviderForSignOut += OnRedirectToIdentityProviderForSignOutFunc;
            options.SaveTokens = true;
        });
    
  4. 在 appsettings.json 配置文件中,将注销重定向 URI 路径添加到 SignedOutCallbackPath 密钥。

    "AzureAdB2C": {
      "Instance": "https://<your-tenant-name>.b2clogin.com",
      "ClientId": "<web-app-application-id>",
      "Domain": "<your-b2c-domain>",
      "SignedOutCallbackPath": "/signout/<your-sign-up-in-policy>",
      "SignUpSignInPolicyId": "<your-sign-up-in-policy>"
    }
    

在以上示例中,传递给注销请求的 post_logout_redirect_uri 的格式为:https://your-app.com/signout/<your-sign-up-in-policy>。 必须将此 URL 添加到应用程序注册的答复 URL。

基于角色的访问控制

借助 ASP.NET Core 中的授权,可以使用以下方法之一来检查用户是否有权访问受保护的资源:

ConfigureServices 方法中添加 AddAuthorization 方法,以添加授权模型。 以下示例将创建一个名为 EmployeeOnly 的策略。 该策略会检查以验证声明 EmployeeNumber 是否存在。 声明的值必须是以下 ID 之一:1、2、3、4 或 5。

services.AddAuthorization(options =>
    {
        options.AddPolicy("EmployeeOnly", policy =>
              policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
    });

可以使用 AuthorizeAttribute 及其各种参数控制 ASP.NET Core 中的授权。 在其最基本的形式中,通过向控制器、操作或 Razor 页面应用 Authorize 属性,可限制为仅允许该组件的已验证用户访问。

可以使用具有策略名称的 Authorize 属性将策略应用到控制器。 以下代码将 Claims 操作限制为仅允许由 EmployeeOnly 策略授权的用户访问:

[Authorize(Policy = "EmployeeOnly")]
public IActionResult Claims()
{
    return View();
}

后续步骤