在Azure AD B2C中,如何在首次从社交登录登录时将社交帐户链接到任何现有本地帐户? [英] In Azure AD B2C, How do i link a social account with any existing local account during first time sign in from social login?

查看:11
本文介绍了在Azure AD B2C中,如何在首次从社交登录登录时将社交帐户链接到任何现有本地帐户?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用社交帐户Facebook登录时,我希望检查是否已经有本地帐户-使用自定义策略。如果是,则用户必须登录该帐户,才能将其链接到社交帐户,否则将中止社交登录。

如果还没有本地帐户,只需按照说明创建社交帐户和使用随机密码的本地帐户here

已经存在一个堆栈溢出问题,该问题与here非常相似,但它始终需要登录到我不想要的本地帐户,并且谈论对我毫无意义的&qot;SQL标识服务。

推荐答案

我以Wojtekdo的TechnicalProfile为起点,仔细阅读关于自定义配置文件的MS documents,并着眼于我想要做的事情,成功地实现了这一点。我还从Jas Suri的评论中提供的link中提取了用户身份的概念。

我使用子旅程将社交帐户与本地帐户合并,只是为了将其与主要旅程分开。

请注意,我不验证或要求提供本地帐户的密码。我认为这是可以接受的,因为用户在创建Facebook帐户时已经验证了电子邮件的所有权。不过,我更愿意验证本地帐户,并且我有Stackoverflow question如何执行此操作。

为实现此目的,TrustFramework扩展了XML:

<BuildingBlocks>
  <ClaimsSchema>
    <ClaimType Id="userIdentity">
      <DisplayName>userIdentity</DisplayName>
      <DataType>userIdentity</DataType>
      <AdminHelpText>userIdentity</AdminHelpText>
      <UserHelpText>userIdentity</UserHelpText>
    </ClaimType>
    <ClaimType Id="userIdentities">
      <DisplayName>userIdentities</DisplayName>
      <DataType>userIdentityCollection</DataType>
      <AdminHelpText>userIdentities</AdminHelpText>
      <UserHelpText>userIdentities</UserHelpText>
    </ClaimType>
    <ClaimType Id="issuers">
      <DisplayName>issuers</DisplayName>
      <DataType>stringCollection</DataType>
      <UserHelpText>User identity providers. This information is received from alternativeSecurityIds</UserHelpText>
    </ClaimType>
    <ClaimType Id="signInNamesInfo.emailAddress">
      <DisplayName>Email Address</DisplayName>
      <DataType>string</DataType>
      <AdminHelpText>Email address that the user can use to sign in.</AdminHelpText>
      <UserHelpText>Email address to use for signing in.</UserHelpText>
      <UserInputType>TextBox</UserInputType>
    </ClaimType>
    <ClaimType Id="emails">
      <DisplayName>Email Addresses</DisplayName>
      <DataType>stringCollection</DataType>
      <AdminHelpText>Email addresses of the user.</AdminHelpText>
      <UserHelpText>Your email addresses.</UserHelpText>
    </ClaimType>
    <ClaimType Id="strongAuthenticationEmailAddress">
      <DisplayName>Email Address</DisplayName>
      <DataType>string</DataType>
      <AdminHelpText>Email address that the user can use for strong authentication.</AdminHelpText>
      <UserHelpText>Email address to use for strong authentication.</UserHelpText>
      <UserInputType>TextBox</UserInputType>
    </ClaimType>
  </ClaimsSchema>

  <ClaimsTransformations>
    <ClaimsTransformation Id="CreateEmailsFromOtherMailsAndSignInNamesInfo" TransformationMethod="AddItemToStringCollection">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="signInNamesInfo.emailAddress" TransformationClaimType="item" />
        <InputClaim ClaimTypeReferenceId="otherMails" TransformationClaimType="collection" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="emails" TransformationClaimType="collection" />
      </OutputClaims>
    </ClaimsTransformation>
    <ClaimsTransformation Id="AddStrongAuthenticationEmailToEmails" TransformationMethod="AddItemToStringCollection">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" TransformationClaimType="item" />
        <InputClaim ClaimTypeReferenceId="emails" TransformationClaimType="collection" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="emails" TransformationClaimType="collection" />
      </OutputClaims>
    </ClaimsTransformation>
    <ClaimsTransformation Id="CreateSubjectClaimFromObjectID" TransformationMethod="CreateStringClaim">
      <InputParameters>
        <InputParameter Id="value" DataType="string" Value="Not supported currently. Use oid claim." />
      </InputParameters>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="sub" TransformationClaimType="createdClaim" />
      </OutputClaims>
    </ClaimsTransformation>
    <!-- Sample: On sign-in (first time) with social account, create a userIdentity claim, using issuerUserId and issuer name -->
    <ClaimsTransformation Id="CreateUserIdentity" TransformationMethod="CreateUserIdentity">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="issuerUserId" TransformationClaimType="issuerUserId" />
        <InputClaim ClaimTypeReferenceId="identityProvider" TransformationClaimType="issuer" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="userIdentity" TransformationClaimType="userIdentity" />
      </OutputClaims>
    </ClaimsTransformation>
    
    <!--Sample: Add a userIdentity to the userIdentities collection. .-->
    <ClaimsTransformation Id="AppendUserIdentity" TransformationMethod="AddItemToUserIdentityCollection">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="userIdentity" TransformationClaimType="item" />
        <InputClaim ClaimTypeReferenceId="userIdentities" TransformationClaimType="collection" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="userIdentities" TransformationClaimType="collection" />
      </OutputClaims>
    </ClaimsTransformation>

    <!--Sample: Extracts the list of social identity providers associated with the user -->
    <ClaimsTransformation Id="ExtractIssuers" TransformationMethod="GetIssuersFromUserIdentityCollectionTransformation">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="userIdentities" TransformationClaimType="userIdentityCollection" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="issuers" TransformationClaimType="issuersCollection" />
      </OutputClaims>
    </ClaimsTransformation>
  </ClaimsTransformations>
</BuildingBlocks>

<ClaimsProviders>
  <ClaimsProvider>
  <DisplayName>Azure Active Directory</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="AAD-ReadCommon">
      <Metadata>
        <Item Key="Operation">Read</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
      </Metadata>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
        <OutputClaim ClaimTypeReferenceId="displayName" />
        <OutputClaim ClaimTypeReferenceId="otherMails" />
        <OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" PartnerClaimType="signInNames.emailAddress" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="CreateEmailsFromOtherMailsAndSignInNamesInfo" />
        <OutputClaimsTransformation ReferenceId="AddStrongAuthenticationEmailToEmails" />
      </OutputClaimsTransformations>
      <IncludeTechnicalProfile ReferenceId="AAD-Common" />
    </TechnicalProfile>

    <TechnicalProfile Id="AAD-UserReadUsingEmailAddress-NoError">
      <Metadata>
        <Item Key="Operation">Read</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
        <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided user ID.</Item>
      </Metadata>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="logonIdentifier" Required="true" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" />
        <OutputClaim ClaimTypeReferenceId="accountEnabled" />
      </OutputClaims>
      <IncludeTechnicalProfile ReferenceId="AAD-ReadCommon" />
    </TechnicalProfile>

    <TechnicalProfile Id="AAD-AssertAccountEnabledAndCreateSubjectClaimFromObjectId">
      <DisplayName>Assert account enabled</DisplayName>
      <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" Required="true" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" />
        <OutputClaim ClaimTypeReferenceId="accountEnabled" />
        <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
        <OutputClaim ClaimTypeReferenceId="email" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="AssertAccountEnabledIsTrue" />
        <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
      </OutputClaimsTransformations>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
    </TechnicalProfile>

    <TechnicalProfile Id="AAD-UserUpdateWithUserIdentities">
      <Metadata>
        <Item Key="api-version">1.6</Item>
        <Item Key="Operation">Write</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
      </Metadata>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
      </InputClaims>
      <PersistedClaims>
        <PersistedClaim ClaimTypeReferenceId="objectId" />
        <PersistedClaim ClaimTypeReferenceId="userIdentities" />
        <!--<PersistedClaim ClaimTypeReferenceId="extension_requiresMigrationBool" DefaultValue="false" AlwaysUseDefaultValue="true"/>-->
      </PersistedClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" />
        <OutputClaim ClaimTypeReferenceId="userIdentities" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="ExtractIssuers" />
      </OutputClaimsTransformations>
      <IncludeTechnicalProfile ReferenceId="AAD-Common" />
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
    </TechnicalProfile>
    </TechnicalProfiles>
  </ClaimsProvider>

  <ClaimsProvider>
    <DisplayName>Facebook</DisplayName>
    <TechnicalProfiles>
      <TechnicalProfile Id="Facebook-OAUTH">
        <OutputClaimsTransformations>
          <OutputClaimsTransformation ReferenceId="CreateUserIdentity" />
          <OutputClaimsTransformation ReferenceId="AppendUserIdentity" />
        </OutputClaimsTransformations>
      </TechnicalProfile>
    </TechnicalProfiles>
  </ClaimsProvider>
</ClaimsProviders>

<UserJourneys>
  <UserJourney Id="SignUpOrSignIn">
    <OrchestrationSteps>

      <!-- For social IDP authentication, attempt to find the user account in the directory. -->
      <OrchestrationStep Order="4" Type="ClaimsExchange">
        <Preconditions>
          <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
            <Value>authenticationSource</Value>
            <Value>localAccountAuthentication</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
        </Preconditions>
        <ClaimsExchanges>
          <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId-NoError"/>
        </ClaimsExchanges>
      </OrchestrationStep>

      <!-- Find local account using email-->        
      <OrchestrationStep Order="5" Type="ClaimsExchange">
        <Preconditions>
          <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
            <Value>authenticationSource</Value>
            <Value>localAccountAuthentication</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
        </Preconditions>
        <ClaimsExchanges>
          <ClaimsExchange Id="FindLocalAccount" TechnicalProfileReferenceId="AAD-UserReadUsingEmailAddress-NoError"/>
        </ClaimsExchanges>
      </OrchestrationStep>

      <!-- start a subjourney to verify local account if one was found in previous step -->
      <OrchestrationStep Order="6" Type="InvokeSubJourney">
        <Preconditions>
          <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
            <Value>authenticationSource</Value>
            <Value>localAccountAuthentication</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
          <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
            <Value>objectId</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
        </Preconditions>
        <JourneyList>
          <Candidate SubJourneyReferenceId="MergeWithLocalAccount" />
        </JourneyList>
      </OrchestrationStep>

    </OrchestrationSteps>
  </UserJourney>
</UserJourneys>

<SubJourneys>
  <SubJourney Id="MergeWithLocalAccount" Type="Call">
    <OrchestrationSteps>
      <!-- assert any found local account is enabled -->
      <OrchestrationStep Order="1" Type="ClaimsExchange">
        <Preconditions>
          <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
            <Value>authenticationSource</Value>
            <Value>localAccountAuthentication</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
          <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
            <Value>objectId</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
        </Preconditions>
        <ClaimsExchanges>
          <ClaimsExchange Id="AssertLocalAccountEnabled" TechnicalProfileReferenceId="AAD-AssertAccountEnabledAndCreateSubjectClaimFromObjectId"/>
        </ClaimsExchanges>
      </OrchestrationStep>

      <!-- merge account with any existing and verified local account-->
      <OrchestrationStep Order="2" Type="ClaimsExchange">
        <Preconditions>
          <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
            <Value>authenticationSource</Value>
            <Value>localAccountAuthentication</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
          <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
            <Value>objectId</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
            <Value>accountVerified</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
        </Preconditions>
        <ClaimsExchanges>
          <ClaimsExchange Id="AADMergeAccount" TechnicalProfileReferenceId="AAD-UserUpdateWithUserIdentities" />
        </ClaimsExchanges>
      </OrchestrationStep>
    </OrchestrationSteps>
  </SubJourney>
</SubJourneys>

我已经包含了我为解决合并的社交帐户和本地帐户而添加的所有XML,不包括其他所有内容。我知道这不是最小的解决方案,可能不需要某些BIT,但它是一个有效的解决方案,可能会帮助其他人弄清楚。

这篇关于在Azure AD B2C中,如何在首次从社交登录登录时将社交帐户链接到任何现有本地帐户?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆