使用 Azure Active Directory B2C 自定义策略在用户旅程中创建分支

同一应用的不同用户可以遵循不同的用户旅程,具体取决于自定义策略中数据的值。 Azure Active Directory B2C (Azure AD B2C) 自定义策略允许有条件地启用或禁用技术配置文件来实现此功能。 例如,在“使用 Azure AD B2C 自定义策略验证用户输入”中,我们使用 Precondition 确定是否应基于 accountType 声明的值运行验证技术配置文件。

技术配置文件还提供了一个 EnabledForUserJourneys 元素,用于指定是否应运行技术配置文件。 元素 EnabledForUserJourneys 包含五个值之一,其中包括 OnClaimsExistence,用于指定仅当技术配置文件中指定的特定声明存在时才应运行技术配置文件。 详细了解技术配置文件的 EnabledForUserJourneys 元素。

方案概述

在《使用 Azure AD B2C 自定义策略验证用户输入》一文中,用户在单个屏幕中输入其详细信息。 在此文中,用户需要首先选择其帐户类型,即“Contoso 员工帐户”或“个人帐户”。 选择“Contoso 员工帐户”的用户可以继续提供更多详细信息。 但选择“个人帐户”的用户则需要提供有效的邀请访问代码,然后才能继续提供更多详细信息。 因此,使用“个人帐户”帐户类型的用户会看到一个额外的用户界面来完成其旅程。

用户旅程分支流程图。

本文介绍如何使用技术配置文件中的 EnabledForUserJourneys 元素来基于声明值创建不同的用户体验。

先决条件

备注

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

步骤 1 - 发布声明

选择“个人帐户”的用户需要提供有效的访问代码。 因此,我们需要一个声明来保存此值:

  1. 在 VS Code 中,打开 ContosoCustomPolicy.XML 文件。

  2. ClaimsSchema 部分中,使用以下代码声明 accessCode 和 isValidAccessCode 声明:

        <ClaimType Id="accessCode">
            <DisplayName>Access Code</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>Enter your invitation access code.</UserHelpText>
            <UserInputType>Password</UserInputType>
            <Restriction>
                <Pattern RegularExpression="[0-9][0-9][0-9][0-9][0-9]" HelpText="Please enter your invitation access code. It's a 5-digit number, something like 95765"/>
            </Restriction>
        </ClaimType>
        <ClaimType Id="isValidAccessCode">
            <DataType>boolean</DataType>
        </ClaimType>
    

步骤 2 - 定义声明转换

找到 ClaimsTransformations 元素,并添加以下声明转换:

    <!---<ClaimsTransformations>-->
        <ClaimsTransformation Id="CheckIfIsValidAccessCode" TransformationMethod="CompareClaimToValue">
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="accessCode" TransformationClaimType="inputClaim1"/>
            </InputClaims>
            <InputParameters>
                <InputParameter Id="compareTo" DataType="string" Value="88888"/>
                <InputParameter Id="operator" DataType="string" Value="equal"/>
                <InputParameter Id="ignoreCase" DataType="string" Value="true"/>
            </InputParameters>
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="isValidAccessCode" TransformationClaimType="outputClaim"/>
            </OutputClaims>
        </ClaimsTransformation>
        <ClaimsTransformation Id="ThrowIfIsNotValidAccessCode" TransformationMethod="AssertBooleanClaimIsEqualToValue">
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="isValidAccessCode" TransformationClaimType="inputClaim"/>
            </InputClaims>
            <InputParameters>
                <InputParameter Id="valueToCompareTo" DataType="boolean" Value="true"/>
            </InputParameters>
        </ClaimsTransformation>
    <!---</ClaimsTransformations>-->

我们定义了两个声明转换:CheckIfIsValidAccessCode 和 ThrowIfIsNotValidAccessCodeCheckIfIsValidAccessCode 使用 CompareClaimToValue 转换方法将用户的访问代码输入与静态值 88888 进行比较(使用此值进行测试),并将“truefalse”分配给 isValidAccessCode 声明。 ThrowIfIsNotValidAccessCode 检查两个声明中的两个布尔值是否相等,如果它们不相等,则抛出异常。

步骤 3 - 配置或更新技术配置文件

现在,需要两个新的自断言技术配置文件,一个用于收集帐户类型,另一个用于收集用户的访问代码。 还需要一个新的声明转换类型技术配置文件,以通过执行你在步骤 2 中定义的声明转换来验证用户的访问代码。 现在,我们要将帐户类型收集到不同的自断言技术配置文件中,我们需要更新 UserInformationCollector 自断言技术配置文件,以防止它收集帐户类型。

  1. 找到 ClaimsProviders 元素,然后使用以下代码添加新的声明提供程序:

        <!--<ClaimsProviders>-->
            <ClaimsProvider>
                <DisplayName>Technical Profiles to collect user's access code</DisplayName>
                <TechnicalProfiles>
                    <TechnicalProfile Id="AccessCodeInputCollector">
                        <DisplayName>Collect Access Code Input from user Technical Profile</DisplayName>
                        <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
                        <Metadata>
                            <Item Key="ContentDefinitionReferenceId">SelfAssertedContentDefinition</Item>
                            <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">The access code is invalid.</Item>
                            <Item Key="ClaimTypeOnWhichToEnable">accountType</Item>
                            <Item Key="ClaimValueOnWhichToEnable">personal</Item>
                        </Metadata>
                        <DisplayClaims>
                            <DisplayClaim ClaimTypeReferenceId="accessCode" Required="true"/>
                        </DisplayClaims>
                        <OutputClaims>
                            <OutputClaim ClaimTypeReferenceId="accessCode"/>
                        </OutputClaims>
                        <ValidationTechnicalProfiles>
                            <ValidationTechnicalProfile ReferenceId="CheckAccessCodeViaClaimsTransformationChecker"/>
                        </ValidationTechnicalProfiles>
                        <EnabledForUserJourneys>OnClaimsExistence</EnabledForUserJourneys>
                    </TechnicalProfile>
                    <TechnicalProfile Id="CheckAccessCodeViaClaimsTransformationChecker">
                        <DisplayName>A Claims Transformations to check user's access code validity</DisplayName>
                        <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
                        <OutputClaims>
                            <OutputClaim ClaimTypeReferenceId="isValidAccessCode"/>
                        </OutputClaims>
                        <OutputClaimsTransformations>
                            <OutputClaimsTransformation ReferenceId="CheckIfIsValidAccessCode"/>
                            <OutputClaimsTransformation ReferenceId="ThrowIfIsNotValidAccessCode"/>
                        </OutputClaimsTransformations>
                    </TechnicalProfile>
                </TechnicalProfiles>
            </ClaimsProvider>
        <!--</ClaimsProviders>-->
    

    我们配置了两个技术配置文件:AccessCodeInputCollector 和 CheckAccessCodeViaClaimsTransformationChecker。 我们将 CheckAccessCodeViaClaimsTransformationChecker 技术配置文件作为 AccessCodeInputCollector 技术配置文件中的验证技术配置文件来调用。 CheckAccessCodeViaClaimsTransformationChecker 本身的类型为声明转换技术配置文件,它执行我们在步骤 2 中定义的声明转换。

    AccessCodeInputCollector 是一个自断言技术配置文件,用于从用户收集访问代码。 它包含设置为 EnabledForUserJourneys 元素。 其 Metadata 元素包括一个声明 (accountType) 及其激活此技术配置文件的值(personal)。

  2. 找到 ClaimsProviders 元素,然后使用以下代码添加新的声明提供程序:

        <!--<ClaimsProviders>-->
            <ClaimsProvider>
                <DisplayName>Technical Profile to collect user's accountType</DisplayName>
                <TechnicalProfiles>
                    <TechnicalProfile Id="AccountTypeInputCollector">
                        <DisplayName>Collect User Input Technical Profile</DisplayName>
                        <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
                        <Metadata>
                            <Item Key="ContentDefinitionReferenceId">SelfAssertedContentDefinition</Item>
                        </Metadata>
                        <DisplayClaims>
                            <DisplayClaim ClaimTypeReferenceId="accountType" Required="true"/>
                        </DisplayClaims>
                        <OutputClaims>
                            <OutputClaim ClaimTypeReferenceId="accountType"/>
                        </OutputClaims>
                    </TechnicalProfile>
                </TechnicalProfiles>
            </ClaimsProvider>
        <!--</ClaimsProviders>-->
    

    我们配置了一个自声明的技术配置文件 AccountTypeInputCollector,用于收集用户的帐户类型。 它是帐户类型的值,用于确定是否应激活 AccessCodeInputCollector 自断言技术配置文件。

  3. 要防止 UserInformationCollector 自断言技术配置文件收集帐户类型,请找到 UserInformationCollector 自断言技术配置文件,然后执行以下步骤:

    1. DisplayClaims 集合中移除 accountType 显示声明 <DisplayClaim ClaimTypeReferenceId="accountType" Required="true"/>

    2. OutputClaims 集合中移除 accountType 输出声明 <OutputClaim ClaimTypeReferenceId="accountType"/>

更新用户旅程编排步骤

现在,你已设置好技术配置文件,接下来需要更新用户旅程的业务流程步骤:

  1. 找到你的 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="GetMessageClaimsExchange" TechnicalProfileReferenceId="ClaimGenerator"/>
                </ClaimsExchanges>
            </OrchestrationStep>
            <OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/>
        <!--</OrchestrationSteps>-->
    

    编排步骤显示,我们按编排步骤的 Order 属性所示顺序调用技术配置文件。 但如果用户选择“AccessCodeInputCollector”帐户类型,则会激活 技术配置文件。

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

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

步骤 6 - 测试自定义策略

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

  1. 在第一个屏幕中,对于“帐户类型”,选择“个人帐户”。
  2. 对于“访问代码”,输入 88888,然后选择“继续”。
  3. 根据需要输入其余详细信息,然后选择“继续”。 策略完成执行后,会重定向到 https://jwt.ms并看到解码的 JWT。
  4. 重复步骤 5,但这次选择“帐户类型”和“Contoso 员工帐户”,然后按照提示操作。

步骤 3 中,我们使用 EnabledForUserJourneys 元素启用或禁用技术配置文件。 或者,可以使用用户旅程业务流程步骤中的先决条件来执行或跳过业务流程步骤,我们将在本系列后面部分进行介绍。

接下来,了解: