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

时间:2021-03-19 11:00:35

标签: azure azure-active-directory azure-ad-b2c azure-ad-b2c-custom-policy

我需要自定义从 AD B2C 发送给用户的电子邮件,当她/他重置密码时。

我按照这个文档设置了自助密码重置流程,它工作正常: https://docs.microsoft.com/en-us/azure/active-directory-b2c/add-password-reset-policy?pivots=b2c-custom-policy

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

自述文件明确指出它也可以用于密码重置,但代码仅提供了登录电子邮件验证的示例。

我尝试在各种 verificationCode 中添加 OutputClaim TechnicalProfiles,但我无法想象所提供的 javascript 代码所需的自定义 verificationCode 文本框。

我想也许我应该使用特定的 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:我找到了未呈现文本框的原因。它与使用的 ContentDefinition 相关。尽管使用 api.selfasserted.profileupdate 内容定义,但通过使用 api.localaccountpasswordreset 内容定义,将显示该字段。现在我还在努力。

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

2 个答案:

答案 0 :(得分:0)

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 并引用不同的模板。

答案 1 :(得分:-1)

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

        <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 enter image description here