如何使用可选的电子邮件 OTP 实现 Azure AD B2C 身份体验框架登录

How to Implement Azure AD B2C Identity Experience Framework Sign-In with Optional Email OTP

我有一个业务需求,但我没有弄清楚如何实现它。

  1. 用户第一次登录时,他们会收到电子邮件 OTP 的挑战,然后是强制密码重置。
  2. 所有后续登录尝试将仅提示用户输入电子邮件地址和密码(OTP 是一次性用户流程)。

我的问题是编排步骤 1 收集电子邮件地址,然后我通过提供的电子邮件地址查询 AAD 并读取名为 extension_EmailValidated[=37 的扩展属性=]。如果该属性不是 TRUE,B2C 将强制用户进行电子邮件 OTP 验证,但是,编排步骤 2 不会让我预填充先前输入的电子邮件地址输入框并显示 OTP 按钮。它只会让我做一个或另一个(希望有意义)。

我的 UserJourney 看起来像这样

  <UserJourneys>
    <UserJourney Id="B2CSignIn">
      <OrchestrationSteps>
        <!--User enters their email address-->
        <OrchestrationStep Order="1" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="AADEmailDiscovery" TechnicalProfileReferenceId="AAD-EmailDiscovery" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!--User enters their OTP-->
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>extension_EmailVerified</Value>
              <Value>True</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADEmailVerification" TechnicalProfileReferenceId="AAD-EmailVerification" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!--Set extension_EmailVerified to TRUE-->
        <OrchestrationStep Order="3" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>extension_EmailVerified</Value>
              <Value>True</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserWriteEmailVerifiedUsingEmail" TechnicalProfileReferenceId="AAD-UserWriteEmailVerifiedUsingEmail" />
          </ClaimsExchanges>
        </OrchestrationStep>

这是第 1 步和第 2 步的技术资料。

<TechnicalProfile Id="AAD-EmailDiscovery">
  <DisplayName>Initiate Email Address Verification For Local Account</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.localaccountsignup</Item>
    <Item Key="language.button_continue">Continue</Item>
    <Item Key="setting.showCancelButton">False</Item>
  </Metadata>
  <CryptographicKeys>
    <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
  </CryptographicKeys>
  <IncludeInSso>false</IncludeInSso>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="email" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="email" />
    <OutputClaim ClaimTypeReferenceId="extension_EmailVerified" DefaultValue="false" Required="true" />
  </OutputClaims>
  <ValidationTechnicalProfiles>
    <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
  </ValidationTechnicalProfiles>
</TechnicalProfile>

<TechnicalProfile Id="AAD-EmailVerification">
  <DisplayName>Initiate Email Address Verification For Local Account</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.localaccountsignup</Item>
    <Item Key="language.button_continue">Continue</Item>
    <Item Key="setting.showCancelButton">False</Item>
  </Metadata>
  <CryptographicKeys>
    <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
  </CryptographicKeys>
  <IncludeInSso>false</IncludeInSso>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="email" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
  </OutputClaims>
  <ValidationTechnicalProfiles>
    <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
  </ValidationTechnicalProfiles>
</TechnicalProfile>

另一个非常令人困惑的问题是,我可以让 OTP 按钮出现在第 2 步的唯一方法是为 InputClaim 和 OutputClaims 添加“ParterClaimType=Verified.Email”——这毫无意义.

如果我从 InputClaims 和 OutputClaims 中省略“ParterClaimType=Verified.Email”,我可以从步骤 1 中获取要预填充的电子邮件地址。

<InputClaims>
  <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
</InputClaims>
<OutputClaims>
  <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
</OutputClaims>

非常感谢您的建议和指导。

谢谢!

这里的解决方法是让输入文本框readOnly.

通过声明转换发送在登录屏幕上收集的电子邮件,以将其复制到名为 readOnlyEmail 的新声明中。声明应定义为只读。

      <ClaimType Id="readOnlyEmail">
        <DisplayName>Email Address</DisplayName>
        <DataType>string</DataType>
        <UserHelpText/>
        <UserInputType>Readonly</UserInputType>
      </ClaimType>

将电子邮件声明复制到只读声明中

      <ClaimsTransformation Id="CopySignInNameToReadOnly" TransformationMethod="FormatStringClaim">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="signInName" TransformationClaimType="inputClaim" />
        </InputClaims>
        <InputParameters>
          <InputParameter Id="stringFormat" DataType="string" Value="{0}" />
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="readOnlyEmail" TransformationClaimType="outputClaim" />
        </OutputClaims>
      </ClaimsTransformation>

然后使用 OutputClaimsTransformations 节点从您注册的技术配置文件调用声明转换。

      <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CopySignInNameToReadOnly" />
      </OutputClaimsTransformations>

最后在邮箱验证技术配置文件(selfAsserted technical profile)上,传入待验证的readOnly邮箱:

          <InputClaims>
            <InputClaim ClaimTypeReferenceId="readOnlyEmail"/>
          </InputClaims>
          <OutputClaims>
            <!-- Required claims -->
            <OutputClaim ClaimTypeReferenceId="readOnlyEmail" PartnerClaimType="Verified.Email"/>
          </OutputClaims>

这里展示了这个概念: https://github.com/azure-ad-b2c/samples/tree/master/policies/signin-email-verification

您只需在该样本之上添加您的条件逻辑。