Azure AD B2C自定义策略无密码注册登录流程修改咨询
Azure AD B2C 无密码自定义策略(邮箱/手机号二选一)改造方案
一、核心改造方向
基于拆分验证页的示例策略,重点完成以下调整:
- 新增身份选择逻辑,支持用户选择邮箱或手机号发起OTP验证
- 动态控制信息收集页面字段:验证邮箱则收集手机号,验证手机号则收集邮箱
- 移除所有密码相关的用户旅程、技术配置与页面元素
- 统一注册/登录的OTP验证流程,复用核心技术配置
二、注册流程改造步骤
1. 定义身份选择声明与页面
在<BuildingBlocks>的<ClaimsSchema>中添加身份类型声明:
<ClaimType Id="identityType"> <DisplayName>验证方式</DisplayName> <DataType>string</DataType> <UserInputType>RadioSingleSelect</UserInputType> <Restriction> <Enumeration Text="邮箱" Value="email" SelectByDefault="false" /> <Enumeration Text="手机号" Value="phone" SelectByDefault="false" /> </Restriction> </ClaimType>
创建身份选择页面:
<ContentDefinition Id="api.selfasserted.localaccountsignup.identitytype"> <LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri> <RecoveryUri>~/common/default_page_error.html</RecoveryUri> <DataUri>urn:com:microsoft:aad:b2c:elements:selfasserted:1.1.0</DataUri> <Metadata> <Item Key="DisplayName">选择验证方式</Item> </Metadata> </ContentDefinition>
2. 分支触发OTP验证
在注册用户旅程中,添加身份选择步骤后,根据identityType的值分支执行邮箱/手机号OTP验证:
<UserJourney Id="SignUp"> <OrchestrationSteps> <!-- 步骤1:选择身份类型 --> <OrchestrationStep Order="1" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="IdentityTypeExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignUp-IdentityType" /> </ClaimsExchanges> </OrchestrationStep> <!-- 步骤2:手机号OTP验证分支 --> <OrchestrationStep Order="2" Type="ClaimsExchange"> <Preconditions> <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> <Value>identityType</Value> <Value>email</Value> <Action>SkipThisOrchestrationStep</Action> </Precondition> </Preconditions> <ClaimsExchanges> <ClaimsExchange Id="PhoneVerificationExchange" TechnicalProfileReferenceId="PhoneFactor-InputOrVerify" /> </ClaimsExchanges> </OrchestrationStep> <!-- 步骤3:邮箱OTP验证分支 --> <OrchestrationStep Order="3" Type="ClaimsExchange"> <Preconditions> <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> <Value>identityType</Value> <Value>phone</Value> <Action>SkipThisOrchestrationStep</Action> </Precondition> </Preconditions> <ClaimsExchanges> <ClaimsExchange Id="EmailVerificationExchange" TechnicalProfileReferenceId="EmailVerification-InputOrVerify" /> </ClaimsExchanges> </OrchestrationStep> <!-- 步骤4:补全个人信息 --> <OrchestrationStep Order="4" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="SignUpProfileExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignUp-Profile" /> </ClaimsExchanges> </OrchestrationStep> <!-- 后续创建用户、颁发令牌步骤保持不变 --> </OrchestrationSteps> </UserJourney>
3. 动态控制信息收集字段
修改SelfAsserted-LocalAccountSignUp-Profile技术配置,根据identityType隐藏已验证字段,显示互补字段:
<TechnicalProfile Id="SelfAsserted-LocalAccountSignUp-Profile"> <DisplayName>补全个人信息</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> <InputClaims> <InputClaim ClaimTypeReferenceId="identityType" /> <InputClaim ClaimTypeReferenceId="email" /> <InputClaim ClaimTypeReferenceId="phoneNumber" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="givenName" Required="true" DisplayName="名字" /> <OutputClaim ClaimTypeReferenceId="surname" Required="true" DisplayName="姓氏" /> <OutputClaim ClaimTypeReferenceId="country" Required="true" DisplayName="国籍" /> <OutputClaim ClaimTypeReferenceId="passportNumber" Required="true" DisplayName="护照号" /> <!-- 动态显示手机号(验证邮箱时显示) --> <OutputClaim ClaimTypeReferenceId="phoneNumber" Required="true"> <DisplayControl> <DisplayClaim ClaimTypeReferenceId="phoneNumber" ControlClaimType="PhoneNumber"> <PredicateValidationReference Id="PhoneNumber" /> </DisplayClaim> <Preconditions> <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> <Value>identityType</Value> <Value>phone</Value> <Action>Hide</Action> </Precondition> </Preconditions> </DisplayControl> </OutputClaim> <!-- 动态显示邮箱(验证手机号时显示) --> <OutputClaim ClaimTypeReferenceId="email" Required="true"> <DisplayControl> <DisplayClaim ClaimTypeReferenceId="email" ControlClaimType="Email"> <PredicateValidationReference Id="Email" /> </DisplayClaim> <Preconditions> <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> <Value>identityType</Value> <Value>email</Value> <Action>Hide</Action> </Precondition> </Preconditions> </DisplayControl> </OutputClaim> </OutputClaims> <ValidationTechnicalProfiles> <ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" /> </ValidationTechnicalProfiles> </TechnicalProfile>
三、登录流程改造步骤
1. 改造登录输入页
创建支持邮箱/手机号输入的登录技术配置:
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-EmailPhone"> <DisplayName>登录</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> <Item Key="setting.showSignupLink">false</Item> </Metadata> <InputClaims /> <OutputClaims> <OutputClaim ClaimTypeReferenceId="signInName" Required="true" DisplayName="邮箱/手机号" /> </OutputClaims> <ValidationTechnicalProfiles> <ValidationTechnicalProfile ReferenceId="Login-EmailPhone-OTP" /> </ValidationTechnicalProfiles> </TechnicalProfile>
2. 实现自动识别的OTP验证
创建自动判断邮箱/手机号并触发OTP验证的技术配置:
<TechnicalProfile Id="Login-EmailPhone-OTP"> <DisplayName>OTP验证</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> <InputClaims> <InputClaim ClaimTypeReferenceId="signInName" /> </InputClaims> <OutputClaims /> <ValidationTechnicalProfiles> <!-- 读取邮箱用户信息 --> <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress"> <Preconditions> <Precondition Type="IsEmail" ExecuteActionsIf="true"> <Value>signInName</Value> <Action>IncludeThisValidationTechnicalProfile</Action> </Precondition> </Preconditions> </ValidationTechnicalProfile> <!-- 读取手机号用户信息 --> <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingPhoneNumber"> <Preconditions> <Precondition Type="IsPhoneNumber" ExecuteActionsIf="true"> <Value>signInName</Value> <Action>IncludeThisValidationTechnicalProfile</Action> </Precondition> </Preconditions> </ValidationTechnicalProfile> <!-- 触发邮箱OTP验证 --> <ValidationTechnicalProfile ReferenceId="EmailVerification-InputOrVerify"> <Preconditions> <Precondition Type="ClaimExists" ExecuteActionsIf="true"> <Value>email</Value> <Action>IncludeThisValidationTechnicalProfile</Action> </Precondition> </Preconditions> </ValidationTechnicalProfile> <!-- 触发手机号OTP验证 --> <ValidationTechnicalProfile ReferenceId="PhoneFactor-InputOrVerify"> <Preconditions> <Precondition Type="ClaimExists" ExecuteActionsIf="true"> <Value>phoneNumber</Value> <Action>IncludeThisValidationTechnicalProfile</Action> </Precondition> </Preconditions> </ValidationTechnicalProfile> </ValidationTechnicalProfiles> </TechnicalProfile>
3. 调整登录用户旅程
替换原密码登录步骤,改为邮箱/手机号OTP验证流程:
<UserJourney Id="SignIn"> <OrchestrationSteps> <!-- 步骤1:输入邮箱/手机号 --> <OrchestrationStep Order="1" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="SigninExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-EmailPhone" /> </ClaimsExchanges> </OrchestrationStep> <!-- 步骤2:OTP验证 --> <OrchestrationStep Order="2" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="LoginOTPExchange" TechnicalProfileReferenceId="Login-EmailPhone-OTP" /> </ClaimsExchanges> </OrchestrationStep> <!-- 后续颁发令牌步骤保持不变 --> </OrchestrationSteps> </UserJourney>
四、关键注意事项
- 彻底移除所有密码相关的技术配置(如
LocalAccountPasswordLogin)与用户旅程节点 - 分别测试邮箱注册/登录、手机号注册/登录流程,确保互补字段收集逻辑正常
- 调整
ContentDefinition的UI模板,保持三个步骤页面风格统一
内容的提问来源于stack exchange,提问作者Suraj Dhimaan
相关产品推荐
相关产品推荐

