在 Azure Active Directory B2C 中设置 OAuth 2.0 客户端凭据流

开始之前,请使用此页顶部的“选择策略类型”选择器来选择要设置的策略类型。 Azure Active Directory B2C 提供了两种定义用户如何与应用程序交互的方法:通过预定义的用户流,或者通过可完全配置的自定义策略。 对于每种方法,本文中所需的步骤都不同。

OAuth 2.0 客户端凭据授予流允许应用(机密客户端)在调用 Web 资源(例如 REST API)时使用其自己的凭据(而不是模拟用户)进行身份验证。 这种授予通常用于必须在后台运行的服务器间交互,不需要立即与用户交互。 此类应用程序通常称为守护程序或服务帐户。

在客户端凭据流中,由管理员向应用程序本身直接授予权限。 当应用向资源出示令牌时,资源强制应用本身具有执行操作的授权,因为没有用户参与身份验证。 本文介绍授权应用程序调用 API 所需的步骤,以及如何获取调用该 API 所需的令牌。

注意

此功能目前以公共预览版提供。

应用注册概述

若要让应用能够使用客户端机密登录,然后调用 Web API,你需要在 Azure AD B2C 目录中注册两个应用程序。

  • 应用程序注册能让你的应用使用 Azure AD B2C 登录。 此应用注册过程会生成应用程序 ID(也称为“客户端 ID”),将其作为该应用的唯一标识。 你还将创建一个客户端密码,你的应用可使用该密码安全地获取令牌。

  • Web API 注册可使应用调用安全的 Web API。 注册内容包括 Web API 的作用域。 作用域提供了一种方法来管理受保护资源(例如你的 Web API)的访问权限。 然后,你可以向 Web API 范围授予应用程序权限。 在请求访问令牌时,你的应用需要指定请求的 .default 范围参数。 Azure AD B2C 返回授予应用的 Web API 范围。

下图演示了应用体系结构和注册:

关系图:使用 Web API 调用注册和令牌的 Web 应用。

步骤 1:注册 Web API 应用

在此步骤中,将 Web API(应用 2)注册到其范围。 稍后,授予应用程序(应用 1)对这些范围的权限。 如果已有此类应用注册,请跳过此步骤,然后转到下一步:步骤 1.1 定义 Web API 角色(范围)

请按照以下步骤创建 Web API 应用注册(应用 ID: 2):

  1. 登录 Azure 门户

  2. 确保正在使用的目录包含 Azure AD B2C 租户。 在门户工具栏中选择“目录 + 订阅”图标。

  3. 在“门户设置 | 目录+订阅”页上的“目录名称”列表中找到你的 Azure AD B2C 目录,然后选择“切换”。

  4. 在 Azure 门户中,搜索并选择“Azure AD B2C”。

  5. 选择“应用注册”,然后选择“新建注册” 。

  6. 对于名称,请输入应用程序的名称(例如 my-api1) 。 保留“重定向 URI”和“支持的帐户类型”的默认值。

  7. 选择“注册”。

  8. 完成应用注册后,选择“概述”。

  9. 记录“应用程序(客户端) ID”值,以便在稍后配置 Web 应用程序时使用。

    演示如何获取 Web API 应用程序 ID 的屏幕截图。

步骤 1.1 定义 Web API 角色(范围)

在此步骤中,将配置 Web API“应用程序 ID URI”,然后定义“应用角色”。 应用角色由 OAuth 2.0 范围使用并在代表你的 API 的应用程序注册上定义。 你的应用程序使用具有 .default 范围的应用程序 ID URI。 若要定义应用角色,请执行以下步骤:

  1. 选择创建的 Web API,例如 my-api1。

  2. 在“管理”下,选择“公开 API” 。

  3. 选择“应用程序 ID URI”旁边的“设置”链接。 将默认值 (GUID) 替换为一个唯一名称(例如 api),然后选择“保存”。

  4. 复制应用程序 ID URI。 以下屏幕截图显示了如何复制应用程序 ID URI。

    屏幕截图显示如何复制应用程序 ID。

  5. 在“管理”下,选择“清单”以打开应用程序清单编辑器。 在编辑器中,找到 appRoles 设置,并定义面向 applications 的应用角色。 每个应用角色定义都必须为其 id 值提供一个全局唯一标识符 (GUID)。 通过在 Microsoft PowerShell 中运行 new-guid 命令或在线 GUID 生成器来生成新的 GUID。 每个应用角色定义的 value 属性都会出现在范围内,即 scp 声明中。 value 属性不能包含空格。 以下示例演示了两个应用角色:读取和写入。

    "appRoles": [
    {
      "allowedMemberTypes": ["Application"],
      "displayName": "Read",
      "id": "d6a15e20-f83c-4264-8e61-5082688e14c8",
      "isEnabled": true,
      "description": "Readers have the ability to read tasks.",
      "value": "app.read"
    },
    {
      "allowedMemberTypes": ["Application"],
      "displayName": "Write",
      "id": "204dc4ab-51e1-439f-8c7f-31a1ebf3c7b9",
      "isEnabled": true,
      "description": "Writers have the ability to create tasks.",
      "value": "app.write"
    }],
    
  6. 在页面顶部,选择“保存”以保存清单更改。

步骤 2:注册应用程序

要使应用能够使用客户端凭据流通过 Azure AD B2C 登录,可以使用现有的应用程序,或注册一个新应用程序(应用 1)。

如果使用现有应用,请确保该应用的 accessTokenAcceptedVersion 设置为 2

  1. 在 Azure 门户中,搜索并选择“Azure AD B2C”。
  2. 选择“应用注册”,然后从列表中选择现有应用
  3. 在左侧菜单中的“管理”下,选择“清单”打开清单编辑器。
  4. 找到 accessTokenAcceptedVersion 元素,将其值设置为 2
  5. 在页面顶部,选择“保存”以保存更改。

若要创建新的 Web 应用注册,请执行以下步骤:

  1. 在 Azure 门户中,搜索并选择“Azure AD B2C”

  2. 选择“应用注册”,然后选择“新建注册” 。

  3. 输入应用程序的“名称”。 例如,ClientCredentials_app。

  4. 保留其他值不变,然后选择“注册”。

  5. 记录“应用程序(客户端) ID”,以便在后续步骤中使用。

    屏幕截图显示如何获取应用程序 ID。

步骤 2.1 创建客户端机密

为注册的应用创建客户端机密。 你的应用在请求令牌时使用客户端机密来证明其标识。

  1. 在“管理”下,选择“证书和机密”

  2. 选择“新建客户端机密”。

  3. 在“说明”框中输入客户端机密的说明(例如 clientsecret1)。

  4. 在“过期时间”下,选择机密持续生效的时间,然后选择“添加”。

  5. 记下机密的“值”。 将该值用于后面的一个步骤中的配置。

    屏幕截图显示如何复制应用程序机密。

步骤 2.2 为 Web API 授予应用权限

若要向应用(应用 1)授予权限,请执行以下步骤:

  1. 选择“应用注册”,然后选择你创建的应用(应用 1)。

  2. 在“管理”下选择“API 权限”。

  3. 在“已配置权限”下,选择“添加权限”。

  4. 选择“我的 API”选项卡。

  5. 选择应授予 Web 应用程序访问权限的 API(应用 2)。 例如,输入“my-api1”。

  6. 选择“应用程序权限”。

  7. 在“权限”下,展开“应用”,然后选择之前定义的范围(例如,app.read 和 app.write)。

    屏幕截图显示如何授予应用程序 API 权限。

  8. 选择“添加权限”。

  9. 选择“向<租户名称>授予管理员许可”。

  10. 选择 “是”

  11. 选择“刷新”,然后验证两个范围的“状态”下是否均显示“已授予...” 。

步骤 3:获取访问令牌

用户流或自定义策略无需执行启用客户端凭据的特定操作。 Azure AD B2C 用户流和自定义策略都支持客户端凭据流。 如果你尚未这样做,请创建用户流或自定义策略。 然后,使用偏好的 API 开发应用程序生成授权请求。 使用以下信息作为 POST 请求的正文,构造一个与此示例类似的调用:

https://<tenant-name>.b2clogin.cn/<tenant-name>.partner.onmschina.cn/<policy>/oauth2/v2.0/token

  • <tenant-name> 替换为你的 Azure AD B2C 租户名称。 例如,contoso.b2clogin.cn
  • <policy> 替换为用户流或自定义策略的完整名称。 请注意,所有类型的用户流和自定义策略都支持客户端凭据流。 可以使用你拥有的任何用户流或自定义策略,或创建新的用户流或自定义策略,例如注册或登录。
密钥
grant_type client_credentials
client_id 步骤 2 注册应用程序中的客户端 ID。
client_secret 步骤 2.1 创建客户端机密中的客户端机密值。
scope 步骤 1.1 定义 Web API 角色(范围).default 中的应用程序 ID URI。 例如 https://contoso.partner.onmschina.cn/api/.defaulthttps://contoso.partner.onmschina.cn/12345678-0000-0000-0000-000000000000/.default

实际的 POST 请求如以下示例所示:

请求

POST /<tenant-name>.partner.onmschina.cn/B2C_1A_SUSI/oauth2/v2.0/token HTTP/1.1
Host: <tenant-name>.b2clogin.cn
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=33333333-0000-0000-0000-000000000000
&client_secret=FyX7Q~DuPJ...
&scope=https%3A%2F%2Fcontoso.partner.onmschina.cn%2Fapi%2F.default

响应:

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlBFcG5OZDlnUkNWWUc2dUs...",
    "token_type": "Bearer",
    "not_before": 1645172292,
    "expires_in": 3600,
    "expires_on": 1645175892,
    "resource": "33333333-0000-0000-0000-000000000000"
}

了解返回访问令牌声明。 下表列出了与客户端凭据流相关的声明。

声明 说明
aud 标识令牌的目标接收方。 API 的客户端 ID。
sub 与发起请求的应用程序关联的服务主体。 它是授权请求的 client_id 的服务主体。
azp 被授权方 - 向其颁发访问令牌的一方。 发起请求的应用程序的客户端 ID。 它与你在授权请求的 client_id 中指定的值相同。
scp 应用程序 API 公开的范围集(空格分隔符)。 在客户端凭据流中,授权请求要求提供 .default 范围,而令牌包含 API 公开(并由应用管理员同意)的范围列表。 例如,app.read app.write

步骤 3.1 使用脚本获取访问令牌

使用以下 PowerShell 脚本测试配置:

$appId = "<client ID>"
$secret = "<client secret>"
$endpoint = "https://<tenant-name>.b2clogin.cn/<tenant-name>.partner.onmschina.cn/<policy>/oauth2/v2.0/token"
$scope = "<Your API id uri>/.default"
$body = "grant_type=client_credentials&scope=" + $scope + "&client_id=" + $appId + "&client_secret=" + $secret

$token = Invoke-RestMethod -Method Post -Uri $endpoint -Body $body

使用以下 cURL 脚本测试配置:

curl --location --request POST 'https://<your-tenant>.b2clogin.cn/<your-tenant>.partner.onmschina.cn/<policy>/oauth2/v2.0/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--form 'grant_type="client_credentials"' \
--form 'client_id="<client ID>"' \
--form 'client_secret="<client secret>"' \
--form 'scope="<Your API id uri>/.default"'

步骤 4:自定义令牌

此功能仅适用于自定义策略。 对于设置步骤,请在前面的选择器中选择“自定义策略”。

自定义策略提供了一种扩展令牌颁发过程的方法。 若要自定义 OAuth 2.0 客户端凭据的用户旅程,请按照指导如何配置客户端凭据用户旅程操作。 然后,在 JwtIssuer 技术配置文件中,添加 ClientCredentialsUserJourneyId 元数据以及对你创建的用户旅程的引用。

以下示例演示如何将 ClientCredentialsUserJourneyId 添加到令牌颁发者技术配置文件。

<TechnicalProfile Id="JwtIssuer">
  <Metadata>
    <Item Key="ClientCredentialsUserJourneyId">ClientCredentialsJourney</Item>
  </Metadata>
</TechnicalProfile>

以下示例演示客户端凭据用户旅程。 需要第一个和最后一个业务流程步骤。

<UserJourneys>
  <UserJourney Id="ClientCredentialsJourney">
    <OrchestrationSteps>
      <!-- [Required] Do the client credentials -->
      <OrchestrationStep Order="1" Type="ClaimsExchange">
        <ClaimsExchanges>
          <ClaimsExchange Id="ClientCredSetupExchange" TechnicalProfileReferenceId="ClientCredentials_Setup" />
        </ClaimsExchanges>
      </OrchestrationStep>

      <!-- [Optional] Call a REST API or claims transformation -->
      <OrchestrationStep Order="2" Type="ClaimsExchange">
        <ClaimsExchanges>
          <ClaimsExchange Id="TokenAugmentation" TechnicalProfileReferenceId="TokenAugmentation" />
        </ClaimsExchanges>
      </OrchestrationStep>

      <!-- [Required] Issue the access token -->
      <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
    </OrchestrationSteps>
  </UserJourney>
</UserJourneys>