AD B2C - 如何在密码重置流程中设置自定义电子邮件验证

AD B2C - How to set up custom email verification in Password Reset flow

我需要在 she/he 重置密码时自定义从 AD B2C 发送给用户的电子邮件。

我按照此文档设置了自助式密码重置流程,并且运行良好: https://docs.microsoft.com/en-us/azure/active-directory-b2c/add-password-reset-policy?pivots=b2c-custom-policy

为了提供用于密码重置的品牌电子邮件,我遵循此代码,因为看起来唯一的其他选择是使用显示控件,它目前处于 public 预览(所以我不能在生产中使用它们): https://github.com/azure-ad-b2c/samples/tree/master/policies/custom-email-verifcation

readme中明确表示也可以用于密码重置,但代码只是提供了一个验证邮箱登录的例子

我尝试在各种 TechnicalProfiles 中添加 verificationCode OutputClaim,但我无法看到所提供的 [=] 所需的自定义 verificationCode 文本框=63=]代码。

我在想也许我应该使用特定的 ContentDefinition,但我真的很难找到更新自定义策略的正确方法 xml。

更新澄清一下:在注册示例中,验证码添加到LocalAccountSignUpWithLogonEmail TechnicalProfile:

<ClaimsProvider>
        <DisplayName>Local Account</DisplayName>
        <TechnicalProfiles>
          <TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
              <DisplayName>Email signup</DisplayName>
              <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
              <Metadata>
                <!-- Demo: Disable the email verification-->
                <Item Key="EnforceEmailVerification">False</Item>
              </Metadata>
              <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="objectId"/>
                <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true"/>
                
                <!--Demo: Add the verification code claim type-->
                <OutputClaim ClaimTypeReferenceId="verificationCode" Required="true"/>

由于我正在处理密码重置(由以下 SubJourney 策划),我们可以看到它在第一步中引用了 LocalAccountDiscoveryUsingEmailAddress TechnicalProfile

    <SubJourney Id="PasswordReset" Type="Call">
          <OrchestrationSteps>
            <!--Sample: Validate user's email address. Run this step only when user resets the password-->
            <OrchestrationStep Order="1" Type="ClaimsExchange">
              <ClaimsExchanges>
                <ClaimsExchange Id="PasswordResetUsingEmailAddressExchange" TechnicalProfileReferenceId="LocalAccountDiscoveryUsingEmailAddress" />
              </ClaimsExchanges>
            </OrchestrationStep>
    
            <!--Sample: Collect and persist a new password. Run this step only when user resets the password-->
            <OrchestrationStep Order="2" Type="ClaimsExchange">
              <ClaimsExchanges>
                <ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" />
              </ClaimsExchanges>
            </OrchestrationStep>
          </OrchestrationSteps>
        </SubJourney>

因此,我将 verificationCode 添加到 LocalAccountDiscoveryUsingEmailAddress TechnicalProfile:

    <!-- This technical profile forces the user to verify the email address that they provide on the UI. Only after email is verified, the user account is
    read from the directory. -->
    <TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
      <DisplayName>Reset password using email address</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.localaccountpasswordreset</Item>
        <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
      </CryptographicKeys>
      <IncludeInSso>false</IncludeInSso>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="verificationCode" Required="true"/>
        <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
        <OutputClaim ClaimTypeReferenceId="objectId" />
        <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
        <OutputClaim ClaimTypeReferenceId="authenticationSource" />
      </OutputClaims>
      <ValidationTechnicalProfiles>
        <ValidationTechnicalProfile ReferenceId="REST-EmailVerification"/>
        <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
      </ValidationTechnicalProfiles>
    </TechnicalProfile>

但是页面中没有呈现相关的TextBox

更新2:我找到了为什么文本框没有呈现。和used ContentDefinition有关。通过使用 api.selfasserted.profileupdate 内容定义而不是 api.localaccountpasswordreset 内容定义,将显示该字段。现在我还在努力。

更新 3:我能够使用 api.selfasserted.profileupdate 内容定义使其工作。我将在完成与验证 API 的集成后立即 post 完整的解决方案。

verified.email 输出声明与您在密码重置技术配置文件中的 displayControl 的引用交换,即 LocalAccountDiscoveryUsingEmailAddresshttps://docs.microsoft.com/en-us/azure/active-directory-b2c/custom-email-sendgrid#make-a-reference-to-the-displaycontrol

基本上是完全相同的步骤,除了您对 LocalAccountDiscoveryUsingEmailAddress 技术配置文件进行“引用”更改以显示此特定页面上的显示控件,密码的第 1 步中引用了该页面重置旅程以收集和验证用户电子邮件。

        <TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
          <DisplayName>Reset password using email address</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.localaccountpasswordreset</Item>
            <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
          </CryptographicKeys>
          <IncludeInSso>false</IncludeInSso>
          <DisplayClaims>
            <DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
          </DisplayClaims>
          <OutputClaims>
            <!--<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />-->
            <OutputClaim ClaimTypeReferenceId="email" />
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" />

如果您想要使用与注册不同的电子邮件模板来重置密码,请重新创建一个新的 displayControl 并引用不同的模板。

解决方案是对 LocalAccountDiscoveryUsingEmailAddress 技术配置文件使用 api.selfasserted.profileupdate 内容定义(而不是 api.localaccountpasswordreset)。

        <TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
          <DisplayName>Reset password using email address</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.selfasserted.profileupdate</Item>
            <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
            <Item Key="EnforceEmailVerification">false</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
          </CryptographicKeys>
          <IncludeInSso>false</IncludeInSso>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
            <OutputClaim ClaimTypeReferenceId="verificationCode" Required="true" />
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="REST-EmailVerification" />
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
          </ValidationTechnicalProfiles>
        </TechnicalProfile>

它看起来主要是一种解决方法,但它是不使用显示控件的预览功能的唯一选择。

为了进一步保护验证,REST-EmailVerification 验证技术配置文件中有一个 API 端检查,它会重新检查之前在客户端验证的代码:

          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="REST-EmailVerification" />
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
          </ValidationTechnicalProfiles>

此外,我目前正在添加验证码以避免滥用发送逻辑。

只要显示控件普遍可用,我就会推荐我的客户使用它们。

它不能与特定于密码重置的内容定义一起使用的原因是它不支持其他自定义字段: https://docs.microsoft.com/it-it/azure/active-directory-b2c/contentdefinitions