You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改邮箱时检查新邮箱是否已存在?当前配置逻辑异常排查

问题分析

当前逻辑的核心问题:

  • AAD-UserExistUsingEmailCheck仅读取邮箱对应的用户ID,但未判断该ID是否为当前用户,且未主动抛出邮箱已存在的错误。
  • 验证码验证的前置条件逻辑错误:当检测到邮箱存在时跳过验证,这会导致邮箱被占用时反而不验证验证码,也不报错。
  • 未在验证环节触发错误提示,而是依赖后续的ValidationTechnicalProfiles,不符合“点击验证时就抛出错误”的需求。
修复方案

1. 添加声明转换判断邮箱归属

先添加一个ClaimsTransformation,用于对比返回的emailObjectId和当前用户的objectId:

<ClaimsTransformation Id="CheckEmailObjectIdMatchesCurrentUser" TransformationMethod="CompareClaimStrings">
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="inputClaim1" />
    <InputClaim ClaimTypeReferenceId="emailObjectId" TransformationClaimType="inputClaim2" />
  </InputClaims>
  <InputParameters>
    <InputParameter Id="compareTo" DataType="string" Value="NOT_EQUAL" />
    <InputParameter Id="outputClaimDataType" DataType="boolean" />
  </InputParameters>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="emailAlreadyTaken" TransformationClaimType="outputClaim" />
  </OutputClaims>
</ClaimsTransformation>

同时在ClaimTypes里声明emailAlreadyTaken:

<ClaimType Id="emailAlreadyTaken">
  <DisplayName>Email Already Taken</DisplayName>
  <DataType>boolean</DataType>
</ClaimType>

2. 修改AAD-UserExistUsingEmailCheck技术配置文件

调整元数据,确保读取用户信息时,即使邮箱不存在也不报错,但需要返回当前用户的objectId用于对比:

<TechnicalProfile Id="AAD-UserExistUsingEmailCheck">
  <Metadata>
    <Item Key="Operation">Read</Item>
    <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
    <Item Key="ReturnClaimsOnFailure">objectId</Item>
  </Metadata>
  <IncludeInSso>false</IncludeInSso>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="emailObjectId" PartnerClaimType="objectId" />
    <OutputClaim ClaimTypeReferenceId="objectId" />
  </OutputClaims>
  <IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>

3. 调整ChangeEmailVerificationControl的VerifyCode逻辑

修改验证流程:先检查邮箱是否存在,然后判断是否被其他用户占用,若占用则抛出错误,否则继续验证验证码:

<DisplayControl Id="ChangeEmailVerificationControl" UserInterfaceControlType="VerificationControl">
  <!-- 其他配置保持不变 -->
  <Actions>
    <Action Id="SendCode">
      <!-- 原SendCode逻辑不变 -->
    </Action>
    <Action Id="VerifyCode">
      <ValidationClaimsExchange>
        <!-- 1. 检查邮箱是否存在 -->
        <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AAD-UserExistUsingEmailCheck" ContinueOnError="false" />
        <!-- 2. 执行声明转换,判断邮箱是否被其他用户占用 -->
        <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="ClaimsTransformation-CheckEmailAlreadyTaken" ContinueOnError="false" />
        <!-- 3. 验证验证码:仅当邮箱未被占用时执行 -->
        <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="VerifyEmailOtp">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>emailAlreadyTaken</Value>
              <Value>true</Value>
              <Action>SkipThisValidationTechnicalProfile</Action>
            </Precondition>
          </Preconditions>
        </ValidationClaimsExchangeTechnicalProfile>
      </ValidationClaimsExchange>
    </Action>
  </Actions>
</DisplayControl>

需要添加对应的ClaimsTransformation技术配置文件:

<TechnicalProfile Id="ClaimsTransformation-CheckEmailAlreadyTaken">
  <DisplayName>Check if email is already taken by another user</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="emailAlreadyTaken" />
  </OutputClaims>
  <ClaimsTransformations>
    <ClaimsTransformationReference Id="CheckEmailObjectIdMatchesCurrentUser" />
  </ClaimsTransformations>
  <Metadata>
    <Item Key="UserMessageIfClaimsTransformationBooleanValueIsTrue">There is another user with this email address</Item>
  </Metadata>
</TechnicalProfile>

4. 移除后续验证环节的重复检查

因为已经在VerifyCode步骤完成了邮箱占用检查,所以可以从LocalAccountWriteEmailUsingObjectId的ValidationTechnicalProfiles中移除重复检查:

<TechnicalProfile Id="LocalAccountWriteEmailUsingObjectId">
  <!-- 其他配置保持不变 -->
  <ValidationTechnicalProfiles>
    <ValidationTechnicalProfile ReferenceId="AAD-UserWriteEmailUsingObjectId" />
    <ValidationTechnicalProfile ReferenceId="SendEmailChangeEvent" />
  </ValidationTechnicalProfiles>
</TechnicalProfile>
关键逻辑说明
  • 当用户输入验证码点击验证时,先查询目标邮箱对应的用户ID:
    • 如果邮箱不存在,emailObjectId为空,声明转换后emailAlreadyTaken为false,继续执行验证码验证。
    • 如果邮箱存在,对比返回的用户ID和当前用户ID:
      • 若一致(用户输入自己当前的邮箱),emailAlreadyTaken为false,允许验证。
      • 若不一致(邮箱被其他用户占用),emailAlreadyTaken为true,触发错误提示,同时跳过验证码验证。

内容的提问来源于stack exchange,提问作者dani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 11:54:56