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

Azure B2C自定义策略:禁止向已验证邮箱发验证邮件(用户名登录)

Azure B2C自定义策略:用户名登录下实现验证邮箱唯一

核心问题分析

你当前的错误在于用strongAuthenticationEmailAddress做校验——这个属性是用户后续配置MFA时添加的邮箱,并非注册流程中用于验证的邮箱。在用户名登录的自定义策略里,注册时的验证邮箱默认存储在otherMails属性(数组类型),同时还要考虑到其他用户可能把该邮箱作为登录邮箱(signInNames.emailAddress)或MFA邮箱的情况,需要同时校验这三个属性来确保邮箱唯一性。

解决方案配置修改

1. 新增邮箱唯一性查询技术配置文件

替换你原有的AAD-UserReadUsingStrongAuthenticationEmailAddress,创建一个能同时检查三类邮箱属性的查询配置:

<TechnicalProfile Id="AAD-UserReadByEmailExists">
    <Metadata>
        <Item Key="Operation">Read</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
        <!-- 过滤条件:检查邮箱是否存在于登录邮箱、验证邮箱、MFA邮箱中的任意一个 -->
        <Item Key="Filter">signInNames/any(x:x/value eq '{email}') or otherMails/any(x:x eq '{email}') or strongAuthenticationEmailAddress eq '{email}'</Item>
    </Metadata>
    <IncludeInSso>false</IncludeInSso>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="email" Required="true" />
    </InputClaims>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" />
    </OutputClaims>
    <IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>

2. 修改验证控件逻辑

在发送验证码前先执行邮箱唯一性检查,若邮箱已被使用则抛出错误:

<DisplayControls>
    <DisplayControl Id="signupEmailVerificationControl" UserInterfaceControlType="VerificationControl">
        <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" />
        </InputClaims>
        <DisplayClaims>
            <DisplayClaim ClaimTypeReferenceId="email" ControlClaimType="Email" Required="true" />
            <DisplayClaim ClaimTypeReferenceId="verificationCode" ControlClaimType="VerificationCode" Required="true" />
        </DisplayClaims>
        <Actions>
            <Action Id="SendCode">
                <ValidationClaimsExchange>
                    <!-- 第一步:检查邮箱是否已被任何账户使用 -->
                    <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AAD-UserReadByEmailExists" ContinueOnError="false" />
                    <!-- 若查询到用户存在(objectId不为空),抛出邮箱已存在错误 -->
                    <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="Throw-EmailAlreadyExistsError">
                        <Preconditions>
                            <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
                                <Value>objectId</Value>
                                <Action>SkipThisValidationTechnicalProfile</Action>
                            </Precondition>
                        </Preconditions>
                    </ValidationClaimsExchangeTechnicalProfile>
                    <!-- 邮箱未被使用,执行发送验证码 -->
                    <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AadSspr-SendCode" />
                </ValidationClaimsExchange>
            </Action>
            <Action Id="VerifyCode">
                <ValidationClaimsExchange>
                    <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AadSspr-VerifyCode" />
                </ValidationClaimsExchange>
            </Action>
        </Actions>
    </DisplayControl>
</DisplayControls>

3. 添加错误抛出技术配置文件

用于在邮箱重复时显示自定义错误提示:

<!-- 抛出邮箱已存在错误 -->
<TechnicalProfile Id="Throw-EmailAlreadyExistsError">
    <DisplayName>Throw error if email already exists</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="email" />
    </InputClaims>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="email" />
    </OutputClaims>
    <ValidationTechnicalProfiles>
        <ValidationTechnicalProfile ReferenceId="SelfAsserted-ThrowError" />
    </ValidationTechnicalProfiles>
</TechnicalProfile>

<TechnicalProfile Id="SelfAsserted-ThrowError">
    <DisplayName>Throw Error</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="UserMessageIfClaimsPrincipalAlreadyExists">该邮箱地址 {email} 已被其他账户绑定,请使用其他邮箱。</Item>
    </Metadata>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="email" />
    </InputClaims>
    <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

4. 确保注册时邮箱正确存储

在用户名注册的技术配置文件AAD-UserWriteUsingLogonName中,确认邮箱被映射到otherMails:

<TechnicalProfile Id="AAD-UserWriteUsingLogonName">
    <Metadata>
        <Item Key="Operation">Write</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
        <Item Key="UserMessageIfClaimsPrincipalAlreadyExists">该用户名已被使用,请更换。</Item>
    </Metadata>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.userName" Required="true" />
        <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="otherMails" Required="true" />
        <InputClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password" Required="true" />
        <InputClaim ClaimTypeReferenceId="displayName" Required="true" />
    </InputClaims>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" />
        <OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
        <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
        <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
        <OutputClaim ClaimTypeReferenceId="signInName" />
    </OutputClaims>
    <IncludeTechnicalProfile ReferenceId="AAD-Common" />
    <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:15:23