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

更新Facebook客户端密钥后Azure AD B2C自定义策略出现邮箱重复错误

Azure AD B2C自定义策略Facebook登录重复账户问题修复

问题描述

我已在Azure AD B2C自定义策略中更新了新的Facebook Client Id和Secret。当已在ADB2C租户中注册的用户通过Facebook账户登录时,出现了“Email already exists”错误。我希望修改/更新自定义策略,避免Facebook用户在租户中重复创建账户。此前更新Google Application Client Id后可正常运行,原以为相同流程适用于Facebook IdP,但实际并非如此。

当前策略代码片段

以下是我的扩展策略中显示错误信息的代码片段(来自Starter Pack的标准内容):

<ClaimsProvider>
      <DisplayName>Social accounts</DisplayName>
      <TechnicalProfiles>
        <!-- force unique email address - Collect, validate and return the email address as output claim.           So, next orchestration step will persist the email to the directory            into otherMails attribute -->
        <TechnicalProfile Id="SelfAsserted-SocialEmail">
          <DisplayName>Email signup</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.localaccountsignup</Item>
            <Item Key="language.button_continue">Continue</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    <ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        <!--force unique email address - This technical profile tries to find a local account with provided email address-->
        <TechnicalProfile Id="AAD-UserReadUsingLocalAccountEmail-NoError">
          <Metadata>
            <Item Key="Operation">Read</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames" Required="true" />
          </InputClaims>
          <OutputClaims>
            <!-- Required claims -->
            <OutputClaim ClaimTypeReferenceId="tempObjectId" PartnerClaimType="objectId" />
          </OutputClaims>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
        </TechnicalProfile>
        <!-- force unique email address - This technical profile tries to find a social account with provided email address-->
        <TechnicalProfile Id="AAD-UserReadUsingSocialEmail-NoError">
          <Metadata>
            <Item Key="Operation">Read</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.socialEmailAddress" Required="true" />
          </InputClaims>
          <OutputClaims>
            <!-- Required claims -->
            <OutputClaim ClaimTypeReferenceId="tempObjectId" PartnerClaimType="objectId" />
          </OutputClaims>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    <!-- force unique email address - this technical profile displays the message to the user-->
    <ClaimsProvider>
      <DisplayName>Self Asserted</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="SelfAsserted-UniqueUserMessage">
          <DisplayName>Email unique validation</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>
            <!-- hide the continue and cancel buttons -->
            <Item Key="setting.showContinueButton">false</Item>
            <Item Key="setting.showCancelButton">false</Item>
          </Metadata>
          <!--InputClaimsTransformations>             <InputClaimsTransformation ReferenceId="CreateTheUniqueEmailErrorMessage" />           </InputClaimsTransformations-->
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="uniqueMailUserMessage" />
          </InputClaims>
          <OutputClaims>
            <!-- Show the paragraph claim with the message to the user -->
            <OutputClaim ClaimTypeReferenceId="uniqueMailUserMessage" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

解决方案思路

问题核心在于:更换Facebook应用后,新的Facebook身份提供商返回的用户标识符(sub声明)与旧应用的不同,B2C会将其视为新用户,但该用户的邮箱已存在于租户中,导致冲突。需要修改策略实现邮箱匹配的社交账户链接,而非强制创建新账户。

具体代码修改步骤

1. 更新Facebook技术配置文件

确保获取用户邮箱并持久化到对应属性:

<ClaimsProvider>
  <DisplayName>Facebook</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="Facebook-OAUTH">
      <Metadata>
        <Item Key="client_id">你的新Facebook Client Id</Item>
        <Item Key="scope">email public_profile</Item>
        <Item Key="ClaimsEndpoint">https://graph.facebook.com/v2.9/me?fields=id,first_name,last_name,email</Item>
      </Metadata>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="id" />
        <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
        <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="first_name" />
        <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="last_name" />
        <OutputClaim ClaimTypeReferenceId="displayName" DefaultValue="{givenName} {surname}" />
        <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="facebook.com" />
      </OutputClaims>
      <PersistedClaims>
        <PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.socialEmailAddress" />
      </PersistedClaims>
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

2. 调整用户旅程的账户检查与链接逻辑

在社交登录后添加账户查询与分支处理:

<UserJourney Id="SignUpOrSignIn">
  <OrchestrationSteps>
    <!-- 步骤1:选择身份提供商 -->
    <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
      <ClaimsProviderSelections>
        <ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
      </ClaimsProviderSelections>
    </OrchestrationStep>

    <!-- 步骤2:Facebook登录 -->
    <OrchestrationStep Order="2" Type="ClaimsExchange">
      <ClaimsExchanges>
        <ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAUTH" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- 步骤3:检查邮箱是否存在于本地账户 -->
    <OrchestrationStep Order="3" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
          <Value>tempObjectId</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="CheckLocalAccount" TechnicalProfileReferenceId="AAD-UserReadUsingLocalAccountEmail-NoError" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- 步骤4:检查邮箱是否存在于社交账户 -->
    <OrchestrationStep Order="4" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
          <Value>tempObjectId</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="CheckSocialAccount" TechnicalProfileReferenceId="AAD-UserReadUsingSocialEmail-NoError" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- 步骤5:链接已有账户 -->
    <OrchestrationStep Order="5" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
          <Value>tempObjectId</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="LinkAccount" TechnicalProfileReferenceId="AAD-UserLink" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- 步骤6:创建新账户(如果未找到已有账户) -->
    <OrchestrationStep Order="6" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
          <Value>tempObjectId</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="CreateSocialAccount" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- 后续步骤... -->
  </OrchestrationSteps>
</UserJourney>

3. 确认账户链接技术配置文件存在

确保策略中包含该配置:

<TechnicalProfile Id="AAD-UserLink">
  <Metadata>
    <Item Key="Operation">Link</Item>
    <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
  </Metadata>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="tempObjectId" PartnerClaimType="objectId" Required="true" />
    <InputClaim ClaimTypeReferenceId="alternativeSecurityId" Required="true" />
  </InputClaims>
  <IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>

注意事项

  • 确保所有技术配置文件的引用ID与你的策略结构一致;
  • 测试前备份原有策略,避免配置错误导致服务中断;
  • 验证Facebook应用的权限设置,确保email权限已启用并能正确返回邮箱信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:54:50