我能够通过在 DisplayClaim 中使用 DisplayControl 而不是在 OutputClaim 中使用 Verified.Email 来解决这个用例。
首先在您的 BuildingBlocks、ClaimsSchema 中定义这两个属性:
<BuildingBlocks>
<ClaimsSchema>
<ClaimType Id="readOnlyEmail">
<DisplayName>Email</DisplayName>
<DataType>string</DataType>
<UserInputType>Readonly</UserInputType>
</ClaimType>
<ClaimType Id="verificationCode">
<DisplayName>Secondary Verification Code</DisplayName>
<DataType>string</DataType>
<UserHelpText>Enter your email verification code</UserHelpText>
<UserInputType>TextBox</UserInputType>
</ClaimType>
<!-- Other claims you have defined -->
</ClaimsSchema>
</BuildingBlocks>
我们将把 email 属性复制到 readOnlyEmail 属性中,以便我们可以在屏幕上显示它,并且在验证电子邮件一次性密码 (OTP) 时使用 verifyCode 属性。在这里坚持我。
在 BuildingBlocks 中定义一个 ClaimsTransformation,ClaimsTransformation 通过电子邮件复制到 readOnlyEmail。
<BuildingBlocks>
<!-- ClaimsSchema -->
<ClaimsTransformations>
<ClaimsTransformation Id="CopyEmailAddress" TransformationMethod="CopyClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" TransformationClaimType="inputClaim"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="readOnlyEmail" TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>
</ClaimsTransformations>
<!-- ContentDefinitions, DisplayControls, etc. -->
</BuildingBlocks>
修改 api.selfasserted 的 ContentDefinition 中的 DataUri 元素,使其成为版本 2.0.0 并包含“contract”标签。您必须这样做才能允许 DisplayClaims 工作。
api.selfasserted ContentDefinition 现在应该如下所示:
<BuildingBlocks>
<!-- ClaimsSchema, ClaimsTransformations -->
<ContentDefinitions>
<ContentDefinition Id="api.selfasserted">
<LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.0.0</DataUri>
<Metadata>
<Item Key="DisplayName">Collect information from user page</Item>
</Metadata>
</ContentDefinition>
</ContentDefinitions>
<!-- DisplayControls, etc. -->
</BuildingBlocks>
这里唯一的变化是 ContentDefinition 中的 DataUri 元素。请注意,我们更新了它以包含“合同”一词,它的版本现在是 2.0.0。
然后在 BuildingBlocks 中定义一个 DisplayControl,使用我们的 readOnlyEmail 和 verficationCode ClaimTypes 的 DisplayControls:
<BuildingBlocks>
<!-- ClaimsSchema, ClaimsTransformations, ContentDefinitions, etc -->
<DisplayControls>
<DisplayControl Id="emailVerificationControl" UserInterfaceControlType="VerificationControl">
<InputClaims>
<InputClaim ClaimTypeReferenceId="readOnlyEmail" />
</InputClaims>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="readOnlyEmail" />
<DisplayClaim ClaimTypeReferenceId="verificationCode" ControlClaimType="VerificationCode" />
</DisplayClaims>
<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>
请注意,这里我们显示的是 readOnlyEmail,第二个 DisplayClaim for verificationCode 用于在将 OTP 发送到您的电子邮件后收集它。
还要注意指向我们尚未定义的 TechnicalProfiles 的 Actions。它们对应于屏幕上的按钮,将发送电子邮件并验证代码。接下来让我们定义这些。您可以将它们放在您想要的任何 ClaimsProvider 中:
<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="readOnlyEmail" 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" PartnerClaimType="verificationCode" />
<InputClaim ClaimTypeReferenceId="readOnlyEmail" PartnerClaimType="emailAddress"/>
</InputClaims>
</TechnicalProfile>
这些 TechnicalProfiles 正在利用 AadSsprProtocolProvider 来发送和验证代码。MS在这里有很好的文档:https ://docs.microsoft.com/en-us/azure/active-directory-b2c/aad-sspr-technical-profile
差不多好了。现在让我们创建一个 SelfAssertedAttributeProvider TechnicalProfile 以利用我们新的 DisplayClaim 来进行内联验证。
在您想要的任何 ClaimsProvider 中创建此 TechnicalProfile:
<TechnicalProfile Id="SelfAsserted-VerifyEmail">
<DisplayName>Verify Email</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CopyEmailAddress" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="readOnlyEmail" />
</InputClaims>
<DisplayClaims>
<DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
</DisplayClaims>
</TechnicalProfile>
这个 TechnicalProfile 将 email 作为输入,将其复制到我们的 readOnlyEmail 和 InputClaimsTransformation,然后 readOnlyEmail 用于我们新的 emailVerificationControl DisplayClaim。然后,emailVerficationControl 向用户显示电子邮件的只读值,有一个发送代码的按钮,然后能够在发送后验证它。
您需要做的最后一件事是在您的 UserJourney 中使用这个新的 TechnicalProfile,OrchestrationSteps 如下所示:
<OrchestrationStep Order="X" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-VerifyEmail-CE" TechnicalProfileReferenceId="SelfAsserted-VerifyEmail"/>
</ClaimsExchanges>
</OrchestrationStep>
此技术解决了您遇到问题的用例。