自定义邮件验证导致Azure AD B2C两步式自定义注册策略失效
我搭建了一个两步式自定义注册流程:第一步验证邮箱,第二步设置新密码,原本运行正常。之后我配置了自定义邮件验证器(用DisplayControl实现)来发送自定义内容的验证码,验证码发送功能正常,但添加配置后流程出现异常:第一步无法输出email声明,导致第二步中依赖email的CreateReadonlyEmailClaim声明转换失败。移除第一步TechnicalProfile中的<DisplayClaims>部分后流程恢复正常,请问遗漏了什么配置?
相关配置代码:
<ClaimsTransformation Id="CreateReadonlyEmailClaim" TransformationMethod="FormatStringClaim"> <InputClaims> <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="inputClaim" /> </InputClaims> <InputParameters> <InputParameter Id="stringFormat" DataType="string" Value="{0}" /> </InputParameters> <OutputClaims> <OutputClaim ClaimTypeReferenceId="readonlyEmail" TransformationClaimType="outputClaim" /> </OutputClaims> </ClaimsTransformation> <!-- 2 step partner sign-up --> <TechnicalProfile Id="PartnerSignUpVerifyEmailPage"> <DisplayName>Local Email Verification</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="IpAddressClaimReferenceId">IpAddress</Item> <Item Key="ContentDefinitionReferenceId">api.signUpVerifyEmailPage</Item> <Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">A user with this email address already exists.</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="email" /> </InputClaims> <!-- 添加上这段后流程异常 --> <DisplayClaims> <DisplayClaim DisplayControlReferenceId="emailVerificationControl" /> </DisplayClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" /> </OutputClaims> <ValidationTechnicalProfiles> <!-- 验证邮箱未被注册 --> <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress-RaiseIfExists" /> </ValidationTechnicalProfiles> <IncludeTechnicalProfile ReferenceId="AAD-Common" /> <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" /> </TechnicalProfile> <TechnicalProfile Id="PartnerSignUpSetNewPasswordPage"> <DisplayName>Local Email SignUp</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="IpAddressClaimReferenceId">IpAddress</Item> <Item Key="ContentDefinitionReferenceId">api.signUpSetNewPasswordPage</Item> <Item Key="EnforceEmailVerification">False</Item> </Metadata> <InputClaimsTransformations> <InputClaimsTransformation ReferenceId="CreateReadonlyEmailClaim" /> </InputClaimsTransformations> <InputClaims> <InputClaim ClaimTypeReferenceId="readOnlyEmail" /> </InputClaims> <OutputClaims> <!--OutputClaim ClaimTypeReferenceId="objectId" /> <OutputClaim ClaimTypeReferenceId="readOnlyEmail" /--> <OutputClaim ClaimTypeReferenceId="newPassword" Required="true" /> <OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" /> <OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" /> <OutputClaim ClaimTypeReferenceId="authenticationSource" /> <OutputClaim ClaimTypeReferenceId="newUser" /> </OutputClaims> <ValidationTechnicalProfiles> <ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" /> </ValidationTechnicalProfiles> <IncludeTechnicalProfile ReferenceId="AAD-Common" /> <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" /> </TechnicalProfile>
问题出在使用自定义邮件验证DisplayControl时,未正确配置声明的传递逻辑,导致第一步的email声明无法进入会话传递到第二步。以下是具体修复步骤:
1. 给第一步的TechnicalProfile添加声明解析元数据
在PartnerSignUpVerifyEmailPage的<Metadata>节点中添加以下项,确保系统能正确处理DisplayControl的输出声明:
<Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
2. 确保emailVerificationControl的声明绑定正确
检查你的emailVerificationControl DisplayControl定义,必须包含输入输出的email声明绑定,确保用户输入/验证后的邮箱能被传递回TechnicalProfile:
<DisplayControl Id="emailVerificationControl" DisplayName="Email Verification"> <!-- 接收从TechnicalProfile传入的初始邮箱 --> <InputClaims> <InputClaim ClaimTypeReferenceId="email" /> </InputClaims> <!-- 显示邮箱输入框和验证码输入框 --> <DisplayClaims> <DisplayClaim ClaimTypeReferenceId="email" Required="true" /> <DisplayClaim ClaimTypeReferenceId="verificationCode" ControlClaimType="VerificationCode" Required="true" /> </DisplayClaims> <!-- 输出验证后的邮箱声明,绑定到TechnicalProfile的email声明 --> <OutputClaims> <OutputClaim ClaimTypeReferenceId="email" /> </OutputClaims> <!-- 发送/验证验证码的动作配置 --> <Actions> <Action Id="SendCode"> <ValidationClaimsExchange> <ValidationClaimsExchangeTechnicalProfile ReferenceId="SendVerificationCode" /> </ValidationClaimsExchange> </Action> <Action Id="VerifyCode"> <ValidationClaimsExchange> <ValidationClaimsExchangeTechnicalProfile ReferenceId="VerifyVerificationCode" /> </ValidationClaimsExchange> </Action> </Actions> </DisplayControl>
3. 调整第一步TechnicalProfile的OutputClaims配置
移除OutputClaim中的PartnerClaimType="Verified.Email",因为DisplayControl已经完成验证,直接输出原始email声明即可,确保会话中能保留该声明:
<OutputClaims> <OutputClaim ClaimTypeReferenceId="email" Required="true" /> </OutputClaims>
4. 确认会话管理保留email声明
确保第一步TechnicalProfile使用的SessionManagement(SM-AAD)配置中包含email声明的持久化,默认SM-AAD配置已处理基本声明的保存,若有自定义配置需检查是否遗漏email声明。
完成以上修改后,第一步验证完成后email声明会被正确保存到用户会话中,第二步的CreateReadonlyEmailClaim声明转换就能正常获取到邮箱输入,流程即可恢复正常。
内容的提问来源于stack exchange,提问作者fei0x

