在 Azure AD B2C 中,我如何 link 首次从社交登录登录时已拥有本地帐户的用户的社交帐户?

In Azure AD B2C, How do i link a social account of a user with an already existing local account during first time sign in from social login?

正如我从文档中了解到的那样,Azure AD B2C 会在首次登录时为来自 GMail/Facebook 等社交登录的每个用户创建一个新的本地帐户(如果我错了,请纠正我)。但是,我想通过自定义策略将此和 link 用户拦截到一个已经存在的(用户自己的)本地帐户,而无需创建新的本地帐户。

The Wingtip sample 包含此流程的示例。

参考the "B2C_1A_link" relying party file and the "Link" user journey

请注意,此用户旅程提示最终用户在使用社交帐户登录之前先使用本地帐户登录。

给出了详细的示例here

更新"user identities" 将link 社交帐户与本地帐户。

这可以通过类似于以下的用户旅程来实现。

<UserJourney Id="AccountLinkage">
  <PreserveOriginalAssertion>false</PreserveOriginalAssertion>
  <OrchestrationSteps>
    <!-- Demo: The following orchestration step is always executed. 
         Asks user to sign-in with local account (only)-->
    <OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
      <ClaimsProviderSelections>
        <ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountSigninEmailExchange" />
      </ClaimsProviderSelections>
    </OrchestrationStep>

    <!-- Demo: Sign-in with local account-->
    <OrchestrationStep Order="2" Type="ClaimsExchange">
      <ClaimsExchanges>
        <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- Demo: After user is sign-in, it reads the user, by user object ID,
         from the Azure AD identity store. An error is raised if the user does not exist. -->
    <OrchestrationStep Order="3" Type="ClaimsExchange">
      <ClaimsExchanges>
        <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- Demo: After user is sign-in, and we have the user object ID.
        Now, ask the user to re-sign-in, but this time with
        one of the social account. This orchestration step, displays the sign-in with social
        account buttons.
        Note, You may want to add additional social accounts here-->
    <OrchestrationStep Order="4" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
      <ClaimsProviderSelections>
        **<ClaimsProviderSelection TargetClaimsExchangeId="GoogleExchange" />
        <ClaimsProviderSelection TargetClaimsExchangeId="AmazonAccountExchange" />**
      </ClaimsProviderSelections>
    </OrchestrationStep>

    <!-- Demo: Run the sign-in with social account, based on user choice (from previous step)
        Note, You may want to add additional social accounts here -->
    <OrchestrationStep Order="5" Type="ClaimsExchange">
      <ClaimsExchanges>
        **<ClaimsExchange Id="GoogleExchange" TechnicalProfileReferenceId="Google-OAUTH" />
        <ClaimsExchange Id="AmazonAccountExchange" TechnicalProfileReferenceId="AmazonAccount-OAuth2" />**
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- Demo: Updates the social account for a user, identified by the object
         identifier for the user, in the Azure AD identity store. 
         An error is raised if the user does not exist. -->
    <OrchestrationStep Order="6" Type="ClaimsExchange">
      <ClaimsExchanges>
        <ClaimsExchange Id="AAD-UserWriteUsingAlternativeSecurityId-ThrowIfNotExists" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId-ThrowIfNotExists" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- Demo: Re-reads the user, by user object Id, from the Azure Active Directory.
         An error is raised if the user does not exist. -->
    <OrchestrationStep Order="7" Type="ClaimsExchange">
      <ClaimsExchanges>
        <ClaimsExchange Id="AADUserReadWithObjectIdAfter" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- Demo: Issues a JWT token to the relying party. -->
    <OrchestrationStep Order="8" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
  </OrchestrationSteps>
</UserJourney>

然后创建类似于以下的 'LinkExternalAccount.xml' 策略。

<RelyingParty>
<!-- Demo: This relying party policy executes the `AccountLinkage` user journey.
Please see the B2C_1A_Link_TrustFrameworkExtensions policy for more details -->
<DefaultUserJourney ReferenceId="AccountLinkage" />
<TechnicalProfile Id="PolicyProfile">
  <DisplayName>PolicyProfile</DisplayName>
  <Protocol Name="OpenIdConnect" />
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="displayName" />
    <OutputClaim ClaimTypeReferenceId="givenName" />
    <OutputClaim ClaimTypeReferenceId="surname" />
    <OutputClaim ClaimTypeReferenceId="email" />
    <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
    <OutputClaim ClaimTypeReferenceId="identityProvider" />
  </OutputClaims>
  <SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>

一旦我们 运行 我们的 'Linkexternalaccount.xml' 它将重定向到我们的本地帐户登录,成功登录后,它将要求选择 IDP 并根据用户选择 'User identities' 属性更新。我们可以通过查询用户来检查相同的内容。示例用户身份如下所示,

 **"userIdentities": [
    {
        "issuer": "google.com",
        "issuerUserId": "MTA5MjA5ODQwNzAyNjc3NTEzMzM5"
    }**