编写第一个 Azure Active Directory B2C 自定义策略 - Hello World!

在应用程序中,可以使用用户流来让用户注册、登录或管理其个人资料。 如果用户流未涵盖所有业务特定需求,可使用自定义策略

虽然可以使用预制的自定义策略初用者包来编写自定义策略,但了解如何生成自定义策略非常重要。 本文介绍如何从头开始创建第一个自定义策略。

先决条件

注意

本文是《在 Azure Active Directory B2C 中创建和运行自己的自定义策略操作指南系列教程》的一部分。 建议从第一篇文章开始本系列教程。

步骤 1 - 配置签名和加密密钥

如果尚未这样做,请创建以下加密密钥。 若要自动完成以下演练,请访问 IEF 安装应用,并按照说明操作:

  1. 使用为 Identity Experience Framework 应用程序添加签名和加密密钥中的步骤创建签名密钥。

  2. 使用为标识体验框架应用程序添加签名和加密密钥中的步骤创建加密密钥。

步骤 2 - 生成自定义策略文件

  1. 在 VS Code 中,创建并打开文件 ContosoCustomPolicy.XML

  2. ContosoCustomPolicy.XML 文件中添加以下代码:

        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <TrustFrameworkPolicy
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
          PolicySchemaVersion="0.3.0.0"
          TenantId="yourtenant.partner.onmschina.cn"
          PolicyId="B2C_1A_ContosoCustomPolicy"
          PublicPolicyUri="http://yourtenant.partner.onmschina.cn/B2C_1A_ContosoCustomPolicy">
    
            <BuildingBlocks>
                <!-- Building Blocks Here-->
            </BuildingBlocks>
    
            <ClaimsProviders>
                <!-- Claims Providers Here-->
            </ClaimsProviders>
    
            <UserJourneys>
                <!-- User Journeys Here-->
            </UserJourneys>
    
            <RelyingParty>
                <!-- 
                    Relying Party Here that's your policy’s entry point
                    Specify the User Journey to execute 
                    Specify the claims to include in the token that is returned when the policy runs
                -->
            </RelyingParty>
        </TrustFrameworkPolicy>
    
    

    yourtenant 替换为租户名称的子域部分,例如 contoso。 了解如何获取租户名称

    XML 元素使用策略 ID 和租户名称定义策略文件的顶级 TrustFrameworkPolicy 元素。 TrustFrameworkPolicy 元素包含你将在本系列中使用的其他 XML 元素。

  3. 若要声明声明,请在 ContosoCustomPolicy.XML 文件的 BuildingBlocks 部分中添加以下代码:

      <ClaimsSchema>
        <ClaimType Id="objectId">
            <DisplayName>unique object Id for subject of the claims being returned</DisplayName>
            <DataType>string</DataType>
        </ClaimType>        
        <ClaimType Id="message">
            <DisplayName>Will hold Hello World message</DisplayName>
            <DataType>string</DataType>
        </ClaimType>
      </ClaimsSchema>
    

    声明类似于变量。 声明的声明还显示声明的数据类型

  4. ContosoCustomPolicy.XML 文件的 ClaimsProviders 部分,添加以下代码:

        <ClaimsProvider>
          <DisplayName>Token Issuer</DisplayName>
          <TechnicalProfiles>
            <TechnicalProfile Id="JwtIssuer">
              <DisplayName>JWT Issuer</DisplayName>
              <Protocol Name="None" />
              <OutputTokenFormat>JWT</OutputTokenFormat>
              <Metadata>
                <Item Key="client_id">{service:te}</Item>
                <Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item>
                <Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item>
              </Metadata>
              <CryptographicKeys>
                <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
                <Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer" />
              </CryptographicKeys>
            </TechnicalProfile>
          </TechnicalProfiles>
        </ClaimsProvider>
    
        <ClaimsProvider>
          <!-- The technical profile(s) defined in this section is required by the framework to be included in all custom policies. -->
          <DisplayName>Trustframework Policy Engine TechnicalProfiles</DisplayName>
          <TechnicalProfiles>
            <TechnicalProfile Id="TpEngine_c3bd4fe2-1775-4013-b91d-35f16d377d13">
              <DisplayName>Trustframework Policy Engine Default Technical Profile</DisplayName>
              <Protocol Name="None" />
              <Metadata>
                <Item Key="url">{service:te}</Item>
              </Metadata>
            </TechnicalProfile>
          </TechnicalProfiles>
        </ClaimsProvider>
    

    我们已声明 JWT 令牌颁发者。 在 CryptographicKeys 部分中,如果在步骤 1 中使用不同的名称来配置签名和加密密钥,请确保为 StorageReferenceId 使用正确的值。

  5. ContosoCustomPolicy.XML 文件的 UserJourneys 部分,添加以下代码:

      <UserJourney Id="HelloWorldJourney">
        <OrchestrationSteps>
          <OrchestrationStep Order="1" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
        </OrchestrationSteps>
      </UserJourney>
    

    我们添加了 UserJourney。 用户旅程指定最终用户在 Azure AD B2C 处理请求时所经历的业务逻辑。 此用户旅程只有一个步骤,用于颁发带有下一步中定义的声明的 JTW 令牌。

  6. ContosoCustomPolicy.XML 文件的 RelyingParty 部分,添加以下代码:

      <DefaultUserJourney ReferenceId="HelloWorldJourney"/>
      <TechnicalProfile Id="HelloWorldPolicyProfile">
        <DisplayName>Hello World Policy Profile</DisplayName>
        <Protocol Name="OpenIdConnect" />
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" DefaultValue="abcd-1234-efgh-5678-ijkl-etc."/>
          <OutputClaim ClaimTypeReferenceId="message" DefaultValue="Hello World!"/>
        </OutputClaims>
        <SubjectNamingInfo ClaimType="sub" />
      </TechnicalProfile>
    

    RelyingParty 部分是策略的入口点。 它指定要执行的 UserJourney,以及要包含在策略运行时返回的令牌中的声明。

完成步骤 2 后,ContosoCustomPolicy.XML 文件外观应类似于以下代码:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <TrustFrameworkPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" PolicySchemaVersion="0.3.0.0" TenantId="Contosob2c2233.partner.onmschina.cn" PolicyId="B2C_1A_ContosoCustomPolicy" PublicPolicyUri="http://Contosob2c2233.partner.onmschina.cn/B2C_1A_ContosoCustomPolicy">
        <BuildingBlocks>
            <ClaimsSchema>
            <ClaimType Id="objectId">
                <DisplayName>unique object Id for subject of the claims being returned</DisplayName>
                <DataType>string</DataType>
            </ClaimType>        
            <ClaimType Id="message">
                <DisplayName>Will hold Hello World message</DisplayName>
                <DataType>string</DataType>
            </ClaimType>
            </ClaimsSchema>
        </BuildingBlocks>
        <ClaimsProviders><!--Claims Providers Here-->
            <ClaimsProvider>
                <DisplayName>Token Issuer</DisplayName>
                <TechnicalProfiles>
                    <TechnicalProfile Id="JwtIssuer">
                        <DisplayName>JWT Issuer</DisplayName>
                        <Protocol Name="None"/>
                        <OutputTokenFormat>JWT</OutputTokenFormat>
                        <Metadata>
                            <Item Key="client_id">{service:te}</Item>
                            <Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item>
                            <Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item>
                        </Metadata>
                        <CryptographicKeys>
                            <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer"/>
                            <Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer"/>
                        </CryptographicKeys>
                    </TechnicalProfile>
                </TechnicalProfiles>
            </ClaimsProvider>
    
            <ClaimsProvider>
            <DisplayName>Trustframework Policy Engine TechnicalProfiles</DisplayName>
            <TechnicalProfiles>
                <TechnicalProfile Id="TpEngine_c3bd4fe2-1775-4013-b91d-35f16d377d13">
                <DisplayName>Trustframework Policy Engine Default Technical Profile</DisplayName>
                <Protocol Name="None" />
                <Metadata>
                    <Item Key="url">{service:te}</Item>
                </Metadata>
                </TechnicalProfile>
            </TechnicalProfiles>
            </ClaimsProvider>
        </ClaimsProviders>
      <UserJourneys>
        <UserJourney Id="HelloWorldJourney">
          <OrchestrationSteps>
            <OrchestrationStep Order="1" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
          </OrchestrationSteps>
        </UserJourney>
      </UserJourneys>
        <RelyingParty><!-- 
                Relying Party Here that's your policy’s entry point
                Specify the User Journey to execute 
                Specify the claims to include in the token that is returned when the policy runs
            -->
            <DefaultUserJourney ReferenceId="HelloWorldJourney"/>
            <TechnicalProfile Id="HelloWorldPolicyProfile">
                <DisplayName>Hello World Policy Profile</DisplayName>
                <Protocol Name="OpenIdConnect"/>
                <OutputClaims>
                    <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" DefaultValue="abcd-1234-efgh-5678-ijkl-etc."/>
                    <OutputClaim ClaimTypeReferenceId="message" DefaultValue="Hello World!"/>
                </OutputClaims>
                <SubjectNamingInfo ClaimType="sub"/>
            </TechnicalProfile>
        </RelyingParty>
    </TrustFrameworkPolicy>

步骤 3 - 上传自定义策略文件

  1. 登录 Azure 门户
  2. 如果有权访问多个租户,请选择顶部菜单中的“设置”图标,从“目录 + 订阅”菜单中切换到你的 Azure AD B2C 租户。
  3. 在 Azure 门户中,搜索并选择“Azure AD B2C”。
  4. 在左侧菜单中的“策略”下,选择“Identity Experience Framework”。
  5. 选择“上传自定义策略”,浏览选择,然后上传 ContosoCustomPolicy.XML 文件。

上传文件后,Azure AD B2C 会添加前缀 B2C_1A_,因此名称类似于 B2C_1A_CONTOSOCUSTOMPOLICY。

步骤 4 - 测试自定义策略

  1. 在“自定义策略”下,选择“B2C_1A_CONTOSOCUSTOMPOLICY”。
  2. 对于自定义策略概述页面上的“选择应用程序”,选择 Web 应用程序,例如之前注册的 webapp1。 确保将“选择回复 URL”的值设置为“https://jwt.ms”。
  3. 选择“立即运行”按钮。

策略执行完成后,系统会将你重定向到 https://jwt.ms,然后你会看到已解码的 JWT 令牌。 其外观类似于以下 JWT 令牌代码片段:

    {
      "typ": "JWT",
      "alg": "RS256",
      "kid": "pxLOMWFg...."
    }.{
      ...
      "sub": "abcd-1234-efgh-5678-ijkl-etc.",
      ...
      "acr": "b2c_1a_contosocustompolicy",
      ...
      "message": "Hello World!"
    }.[Signature]

请注意 messagesub 声明,我们在 RelyingParty 部分中将其设置为输出声明

后续步骤

本文介绍了 Azure AD B2C 自定义策略中包含的四个部分。 这些部分作为子元素添加到 TrustFrameworkPolicy 根元素中:

  • BuildingBlocks
  • ClaimsProviders
  • UserJourneys
  • RelyingParty

接下来,了解: