使用 Azure Active Directory B2C 自定义策略创建和读取用户帐户

Azure Active Directory B2C(Azure AD B2C) 基于 Microsoft Entra ID 构建,因此它使用 Microsoft Entra ID 存储来存储用户帐户。 Azure AD B2C 目录用户配置文件附带一组内置属性,例如名字、姓氏、市/县、邮政编码和电话号码,但你可以使用自己的自定义属性扩展用户配置文件,而无需使用外部数据存储。

自定义策略可以使用 Microsoft Entra ID 技术配置文件来存储、更新或删除用户信息,从而连接到 Microsoft Entra ID 存储。 本文介绍如何在返回 JWT 令牌之前配置一组 Microsoft Entra ID 技术配置文件来存储和读取用户帐户。

场景概述

使用 Azure Active Directory B2C 自定义策略调用 REST API 一文中,我们收集了用户的信息、验证了数据、调用了 REST API,最后返回了 JWT,但是没有存储用户帐户。 我们必须存储用户信息,以便在策略完成执行后不会丢失信息。 这一次,在收集并验证用户信息后,我们需要将用户信息存储在 Azure AD B2C 存储中,然后在返回 JWT 令牌之前读取。 下图显示了此完整过程。

在 Azure AD 中创建用户帐户的流程图。

先决条件

注意

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

步骤 1 - 发布声明

需要声明另外两个声明:userPrincipalNamepasswordPolicies

  1. ContosoCustomPolicy.XML 文件中,找到 ClaimsSchema 元素并使用以下代码声明 userPrincipalNamepasswordPolicies 声明:

        <ClaimType Id="userPrincipalName">
            <DisplayName>UserPrincipalName</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>Your user name as stored in the Azure Active Directory.</UserHelpText>
        </ClaimType>
        <ClaimType Id="passwordPolicies">
            <DisplayName>Password Policies</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>Password policies used by Azure AD to determine password strength, expiry etc.</UserHelpText>
        </ClaimType>
    

    详细了解如何使用《用户配置文件属性》一文中的 userPrincipalNamepasswordPolicies 声明。

步骤 2 - 创建 Microsoft Entra ID 技术配置文件

需要配置两个 Microsoft Entra ID 技术配置文件。 一个技术配置文件将用户详细信息写入 Microsoft Entra ID 存储,另一个将从 Microsoft Entra ID 存储读取用户帐户。

  1. ContosoCustomPolicy.XML 文件中,找到 ClaimsProviders 元素,然后使用以下代码添加新的声明提供程序。 此声明提供程序会保存 Microsoft Entra ID 技术配置文件:

        <ClaimsProvider>
            <DisplayName>Azure AD Technical Profiles</DisplayName>
            <TechnicalProfiles>
                <!--You'll add you Azure AD Technical Profiles here-->
            </TechnicalProfiles>
        </ClaimsProvider>
    
  2. 在刚刚创建的声明提供程序中,使用以下代码添加 Microsoft Entra ID 技术配置文件:

        <TechnicalProfile Id="AAD-UserWrite">
            <DisplayName>Write user information to AAD</DisplayName>
            <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
            <Metadata>
                <Item Key="Operation">Write</Item>
                <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
                <Item Key="UserMessageIfClaimsPrincipalAlreadyExists">The account already exists. Try to create another account</Item>
            </Metadata>
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
            </InputClaims>
            <PersistedClaims>
                <PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />        
                <PersistedClaim ClaimTypeReferenceId="displayName" />
                <PersistedClaim ClaimTypeReferenceId="givenName" />
                <PersistedClaim ClaimTypeReferenceId="surname" />
                <PersistedClaim ClaimTypeReferenceId="password"/>
                <PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration,DisableStrongPassword" />
            </PersistedClaims>
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="objectId" />
                <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
                <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
            </OutputClaims>
        </TechnicalProfile>
    

    我们添加了一个新的 Microsoft Entra ID 技术配置文件 AAD-UserWrite。 需要记下技术配置文件的以下重要部分:

    • 操作:操作指定要执行的操作,在本例中为写入。 详细了解 Microsoft Entra ID 技术提供程序中的其他操作

    • 持久化声明:PersistedClaims 元素包含应存储在 Microsoft Entra ID 存储中的所有值。

    • InputClaimsInputClaims 元素包含一个声明,用于在目录中查找帐户,或创建一个新帐户。 所有 Microsoft Entra ID 技术配置文件的输入声明集合中必须有且只有一个输入声明元素。 此技术配置文件使用电子邮件声明作为用户帐户的密钥标识符。 详细了解可用于唯一标识用户帐户的其他密钥标识符

  3. ContosoCustomPolicy.XML 文件中,找到 AAD-UserWrite 技术配置文件,然后使用以下代码在其后面添加一个新的技术配置文件:

        <TechnicalProfile Id="AAD-UserRead">
            <DisplayName>Read user from Azure AD storage</DisplayName>
            <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
            <Metadata>
                <Item Key="Operation">Read</Item>
                <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
                <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
            </Metadata>
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
            </InputClaims>
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="objectId" />
                <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
                <OutputClaim ClaimTypeReferenceId="givenName"/>
                <OutputClaim ClaimTypeReferenceId="surname"/>
                <OutputClaim ClaimTypeReferenceId="displayName"/>
            </OutputClaims>
        </TechnicalProfile>
    

    我们添加了一个新的 Microsoft Entra ID 技术配置文件 AAD-UserRead。 我们已将此技术配置文件配置为执行读取操作,并在找到 InputClaim 部分中包含 email 的用户帐户时返回 objectIduserPrincipalNamegivenNamesurnamedisplayName

步骤 3 - 使用 Microsoft Entra ID 技术配置文件

使用 UserInformationCollector 自断言技术配置文件收集用户详细信息后,需要使用 AAD-UserWrite 技术配置文件将用户帐户写入 Microsoft Entra ID 存储。 为此,请将 AAD-UserWrite 技术配置文件用作 UserInformationCollector 自断言技术配置文件中的验证技术配置文件。

ContosoCustomPolicy.XML 文件中,找到 UserInformationCollector 技术配置文件,然后将 AAD-UserWrite 技术配置文件添加为 ValidationTechnicalProfiles 集合中的验证技术配置文件。 需要在 CheckCompanyDomain 验证技术配置文件之后添加此文件。

在颁发 JWT 令牌之前,我们将使用用户旅程业务流程步骤中的 AAD-UserRead 技术配置文件来读取用户详细信息。

步骤 4 - 更新 ClaimGenerator 技术配置文件

我们使用 ClaimGenerator 技术配置文件执行三个声明转换:GenerateRandomObjectIdTransformationCreateDisplayNameTransformationCreateMessageTransformation

  1. ContosoCustomPolicy.XML 文件中,找到 ClaimGenerator 技术配置文件并将其替换为以下代码:

        <TechnicalProfile Id="UserInputMessageClaimGenerator">
            <DisplayName>User Message Claim Generator Technical Profile</DisplayName>
            <Protocol Name="Proprietary"
                Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="message" />
            </OutputClaims>
            <OutputClaimsTransformations>
                <OutputClaimsTransformation ReferenceId="CreateMessageTransformation" />
            </OutputClaimsTransformations>
        </TechnicalProfile>
    
        <TechnicalProfile Id="UserInputDisplayNameGenerator">
            <DisplayName>Display Name Claim Generator Technical Profile</DisplayName>
            <Protocol Name="Proprietary"
                Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="displayName" />
            </OutputClaims>
            <OutputClaimsTransformations>
                <OutputClaimsTransformation ReferenceId="CreateDisplayNameTransformation" />
            </OutputClaimsTransformations>
        </TechnicalProfile>
    

    我们已将该技术配置文件分解为两个单独的技术配置文件。 UserInputMessageClaimGenerator 技术配置文件会在 JWT 令牌中生成作为声明发送的消息。 UserInputDisplayNameGenerator 技术配置文件可生成 displayName 声明。 在 AAD-UserWrite 技术配置文件将用户记录写入 Microsoft Entra ID 存储之前,displayName 声明值必须可用。 在新代码中,我们将删除 GenerateRandomObjectIdTransformation,因为创建帐户后由 Microsoft Entra ID 创建并返回 objectId,因此无需在策略中自行生成它。

  2. ContosoCustomPolicy.XML 文件中,找到 UserInformationCollector 自断言技术配置文件,然后将 UserInputDisplayNameGenerator 技术配置文件添加为验证技术配置文件。 执行此操作后,UserInformationCollector 技术配置文件的 ValidationTechnicalProfiles 集合外观应类似于以下代码:

        <!--<TechnicalProfile Id="UserInformationCollector">-->
            <ValidationTechnicalProfiles>
                <ValidationTechnicalProfile ReferenceId="CheckCompanyDomain">
                    <Preconditions>
                        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
                            <Value>accountType</Value>
                            <Value>work</Value>
                            <Action>SkipThisValidationTechnicalProfile</Action>
                        </Precondition>
                    </Preconditions>
                </ValidationTechnicalProfile>                        
                <ValidationTechnicalProfile ReferenceId="UserInputDisplayNameGenerator"/>
                <ValidationTechnicalProfile ReferenceId="AAD-UserWrite"/>
            </ValidationTechnicalProfiles>
        <!--</TechnicalProfile>-->
    

    必须在 AAD-UserWrite 之前添加验证技术配置文件,因为在 AAD-UserWrite 技术配置文件将用户记录写入 Microsoft Entra ID 存储之前,displayName 声明值必须可用。

步骤 5 - 更新用户旅程业务流程步骤

找到 HelloWorldJourney 用户旅程,并将所有业务流程步骤替换为以下代码:

    <!--<OrchestrationSteps>-->
        <OrchestrationStep Order="1" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="AccountTypeInputCollectorClaimsExchange" TechnicalProfileReferenceId="AccountTypeInputCollector"/>
            </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="GetAccessCodeClaimsExchange" TechnicalProfileReferenceId="AccessCodeInputCollector" />
            </ClaimsExchanges>
            </OrchestrationStep>
        <OrchestrationStep Order="3" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="GetUserInformationClaimsExchange" TechnicalProfileReferenceId="UserInformationCollector"/>
            </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="4" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="AADUserReaderExchange" TechnicalProfileReferenceId="AAD-UserRead"/>
            </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="5" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="UserInputMessageClaimGenerator"/>
            </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/>
    <!--</OrchestrationSteps>-->

在业务流程步骤 4 中,我们将执行 AAD-UserRead 技术配置文件,以从创建的用户帐户读取(要包含在 JWT 令牌中的)用户详细信息。

由于我们不会存储 message 声明,因此在业务流程步骤 5中,我们将执行 UserInputMessageClaimGenerator 以生成 JWT 令牌上要包含的 message 声明。

步骤 6 - 上传策略

按照上传自定义策略文件中的步骤上传策略文件。 如果要上传与门户中已有文件同名的文件,请确保选择“覆盖自定义策略(若已有)”。

步骤 7 - 测试策略

按照测试自定义策略中的步骤测试自定义策略。

在策略完成执行并收到 ID 令牌后,检查是否已创建用户记录:

  1. 登录到 Azure 门户

  2. 如果有权访问多个租户,请选择顶部菜单中的“设置”图标,从“目录 + 订阅”菜单切换到你的 Azure AD B2C 租户。

  3. 在“Azure 服务”下,选择“Azure AD B2C”。 或者,使用搜索框查找并选择“Azure AD B2C”。

  4. 在“管理”下,选择“用户” 。

  5. 找到刚刚创建的用户帐户,并将其选中。 帐户配置文件外观类似于下面的屏幕截图:

    在 Azure AD 中创建用户帐户的屏幕截图。

在 Microsoft Entra ID 技术配置文件 AAD-UserWrite 中,我们指定如果用户已存在,会引发错误消息。

使用相同的电子邮件地址再次测试自定义策略。 应看到类似于以下屏幕截图的错误消息,而不是执行到完成状态以颁发 ID 令牌的策略。

由于帐户已存在而引发的错误的屏幕截图。

注意

密码声明值是一条非常重要的信息,因此在自定义策略中处理该信息时务必谨慎操作。 出于类似的原因,Azure AD B2C 将密码声明值视为特殊值。 在自断言技术配置文件中收集密码声明值时,该值仅在同一技术配置文件中,或由同一自断言技术配置文件引用的验证技术配置文件中可用。 该自断言技术配置文件的执行完成并移动到另一个技术配置文件后,该值将丢失。

验证用户电子邮件地址

建议先验证用户的电子邮件,然后再使用它来创建用户帐户。 验证电子邮件地址时,请确保帐户是由真实用户创建的。 你还可以帮助用户确保他们使用正确的电子邮件地址创建帐户。

Azure AD B2C 的自定义策略提供了一种使用验证显示控件来验证电子邮件地址的方法。 向电子邮件发送验证码。 发送代码后,用户将阅读消息、将验证码输入到显示控件提供的控件中,然后选择“验证代码”按钮。

显示控件是一个具有特殊功能的用户界面元素,可以与 Azure Active Directory B2C (Azure AD B2C) 后端服务进行交互。 它允许用户在页面上执行某些操作,这些操作在后端调用验证技术配置文件。 显示控件显示在页面上,由自断言技术配置文件引用。

要使用显示控件添加电子邮件验证,请使用以下步骤:

发布声明

你需要声明要用于保留验证码的声明。

要发布声明,请在 ContosoCustomPolicy.XML 文件中找到 ClaimsSchema 元素,并使用以下代码声明 verificationCode 声明:

    <!--<ClaimsSchema>-->
        ...
        <ClaimType Id="verificationCode">
            <DisplayName>Verification Code</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>Enter your verification code</UserHelpText>
            <UserInputType>TextBox</UserInputType>
        </ClaimType>
    <!--</ClaimsSchema>-->

配置发送和验证代码技术配置文件

Azure AD B2C 使用 Microsoft Entra ID SSPR 技术配置文件来验证电子邮件地址。 根据配置方式,此技术配置文件可以生成代码并将其发送到电子邮件地址或验证代码。

ContosoCustomPolicy.XML 文件中,找到 ClaimsProviders 元素,然后使用以下代码添加声明提供程序:

    <ClaimsProvider>
        <DisplayName>Azure AD self-service password reset (SSPR)</DisplayName>
        <TechnicalProfiles>
            <TechnicalProfile Id="AadSspr-SendCode">
            <DisplayName>Send Code</DisplayName>
            <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AadSsprProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
            <Metadata>
                <Item Key="Operation">SendCode</Item>
            </Metadata>
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailAddress" />
            </InputClaims>
            </TechnicalProfile>
            <TechnicalProfile Id="AadSspr-VerifyCode">
            <DisplayName>Verify Code</DisplayName>
            <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AadSsprProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
            <Metadata>
                <Item Key="Operation">VerifyCode</Item>
            </Metadata>
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="verificationCode" />
                <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailAddress" />
            </InputClaims>
            </TechnicalProfile>
        </TechnicalProfiles>
    </ClaimsProvider>

我们配置了两个技术配置文件 AadSspr-SendCodeAadSspr-VerifyCodeAadSspr-SendCode 会生成代码并将其发送到 InputClaims 部分中指定的电子邮件地址,而 AadSspr-VerifyCode 会验证代码。 指定要在技术配置文件元数据中执行的操作。

配置显示控件

需要配置电子邮件验证显示控件才能验证用户电子邮件。 所配置的电子邮件验证显示控件将替换用于收集用户电子邮件的电子邮件显示声明。

要配置显示控件,请使用以下步骤:

  1. ContosoCustomPolicy.XML 文件中,找到 BuildingBlocks 部分,然后使用以下代码将显示控件添加为子元素:

        <!--<BuildingBlocks>-->
            ....
            <DisplayControls>
                <DisplayControl Id="emailVerificationControl" UserInterfaceControlType="VerificationControl">
                  <DisplayClaims>
                    <DisplayClaim ClaimTypeReferenceId="email" Required="true" />
                    <DisplayClaim ClaimTypeReferenceId="verificationCode" ControlClaimType="VerificationCode" Required="true" />
                  </DisplayClaims>
                  <OutputClaims></OutputClaims>
                  <Actions>
                    <Action Id="SendCode">
                      <ValidationClaimsExchange>
                        <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AadSspr-SendCode" />
                      </ValidationClaimsExchange>
                    </Action>
                    <Action Id="VerifyCode">
                      <ValidationClaimsExchange>
                        <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AadSspr-VerifyCode" />
                      </ValidationClaimsExchange>
                    </Action>
                  </Actions>
                </DisplayControl>
            </DisplayControls> 
        <!--</BuildingBlocks>-->
    

    我们已声明显示控件 emailVerificationControl。 请注意以下重要部分:

    • DisplayClaims - 就像在自断言技术配置文件中一样,本部分指定了要从显示控件中的用户收集的声明集合。

    • 操作 - 指定要由显示控件执行的操作顺序。 每个操作会引用负责执行该操作的技术配置文件。 例如,SendCode 引用 AadSspr-SendCode 技术配置文件,该配置文件会生成代码并将其发送到电子邮件地址。

  2. ContosoCustomPolicy.XML 文件中,找到 UserInformationCollector 自断言技术配置文件,并将电子邮件显示声明替换为 emailVerificationControl 显示控件:

    发件人:

        <DisplayClaim ClaimTypeReferenceId="email" Required="true"/>
    

    到:

        <DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
    
  3. 使用步骤 6步骤 7 中的过程上传并测试策略文件。 这一次,必须在创建用户帐户之前验证电子邮件地址。

使用 Microsoft Entra ID 技术配置文件更新用户帐户

可以将 Microsoft Entra ID 技术配置文件配置为更新用户帐户,而不是尝试创建新帐户。 为此,请使用以下代码设置 Microsoft Entra ID 技术配置文件,以便在元数据集合中尚不存在指定用户帐户时引发错误。 此外,请删除 Key="UserMessageIfClaimsPrincipalAlreadyExists 元数据条目。 需要将“操作”设置为“写入”:

    <Item Key="Operation">Write</Item>
    <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>

使用自定义属性

在本文中,你已了解了如何使用内置用户配置文件属性存储用户详细信息。 但你通常需要创建自己的自定义属性来管理特定方案。 为此,请按照《在 Azure Active Directory B2C 中定义自定义属性》一文中的说明进行操作。

后续步骤