Azure Active Directory B2C 사용자 지정 정책을 사용하여 소셜 계정으로 등록 및 로그인 흐름 설정

Azure Active Directory B2C 사용자 지정 정책을 사용하여 등록 및 로그인 흐름 설정 문서에서는 Azure AD B2C(Azure Active Directory B2C)를 사용하여 로컬 계정에 대한 로그인 흐름을 설정합니다.

이 문서에서는 Facebook 등의 소셜 계정과 같은 외부 계정에 대한 로그인 흐름을 추가합니다. 이 경우 Azure AD B2C를 사용하면 사용자가 외부 소셜 IdP(ID 공급자)의 자격 증명을 사용하여 애플리케이션에 로그인할 수 있습니다.

로컬 계정의 경우 사용자 계정은 objectId사용자 특성을 사용하여 고유하게 식별됩니다. 외부 IdP의 경우 objectId가 여전히 존재하지만 alternativeSecurityId 사용자 특성을 사용합니다.

필수 조건

참고 항목

이 문서는 Azure Active Directory B2C 방법 가이드 시리즈에서 사용자 고유의 사용자 지정 정책 만들기 및 실행의 일부입니다. 이 시리즈는 첫 번째 문서부터 시작하는 것이 좋습니다.

1단계 - Facebook 애플리케이션 만들기

Facebook 애플리케이션 만들기에 설명된 단계를 사용하여 Facebook 앱 ID앱 비밀을 가져옵니다. Facebook 계정으로 가입 및 로그인 설정 문서의 필수 조건과 나머지 단계를 건너뜁니다.

2단계 - Facebook 정책 키 만들기

Facebook 키 만들기에 설명된 단계를 사용하여 Azure AD B2C 테넌트에서 정책 키를 저장합니다. Facebook 계정으로 가입 및 로그인 설정 문서의 필수 조건과 나머지 단계를 건너뜁니다.

3단계 - Facebook으로 로그인 구성

Facebook으로 로그인을 구성하려면 다음 단계를 수행해야 합니다.

  • 추가 클레임을 선언합니다.
  • AlternativeSecurityId 만들기와 같은 클레임 조작에 도움이 되는 추가 클레임 변환을 정의합니다.
  • Facebook 클레임 공급자 구성
  • Microsoft Entra 데이터베이스에서 소셜 계정을 읽고 쓰도록 Microsoft Entra 기술 프로필을 구성합니다.
  • 자체 어설션된 기술 프로필(사용자의 추가 입력 수락 또는 사용자 세부 정보 업데이트) 및 해당 콘텐츠 정의를 구성합니다.

3.1단계 - 추가 클레임 선언

ContosoCustomPolicy.XML 파일에서 ClaimsSchema 섹션을 찾은 후, 다음 코드를 사용하여 추가 클레임을 선언합니다.

    <!--<ClaimsSchema>-->
        ...
        <ClaimType Id="issuerUserId">
            <DisplayName>Username</DisplayName>
            <DataType>string</DataType>
            <UserHelpText/>
            <UserInputType>TextBox</UserInputType>
            <Restriction>
                <Pattern RegularExpression="^[a-zA-Z0-9]+[a-zA-Z0-9_-]*$" HelpText="The username you provided is not valid. It must begin with an alphabet or number and can contain alphabets, numbers and the following symbols: _ -" />
            </Restriction>
        </ClaimType>
        
        <ClaimType Id="identityProvider">
            <DisplayName>Identity Provider</DisplayName>
            <DataType>string</DataType>
            <UserHelpText/>
        </ClaimType>
        
        <ClaimType Id="authenticationSource">
            <DisplayName>AuthenticationSource</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>Specifies whether the user was authenticated at Social IDP or local account.</UserHelpText>
        </ClaimType>  
        
        <ClaimType Id="upnUserName">
            <DisplayName>UPN User Name</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>The user name for creating user principal name.</UserHelpText>
        </ClaimType>
        
        <ClaimType Id="alternativeSecurityId">
            <DisplayName>AlternativeSecurityId</DisplayName>
            <DataType>string</DataType>
            <UserHelpText/>
        </ClaimType>
        
        <ClaimType Id="mailNickName">
            <DisplayName>MailNickName</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>Your mail nick name as stored in the Azure Active Directory.</UserHelpText>
        </ClaimType>
        
        <ClaimType Id="newUser">
            <DisplayName>User is new or not</DisplayName>
            <DataType>boolean</DataType>
            <UserHelpText/>
        </ClaimType>
    <!--</ClaimsSchema>-->

3.2단계 - 클레임 변환 정의

ContosoCustomPolicy.XML 파일에서 ClaimsTransformations 요소를 찾고 다음 코드를 사용하여 클레임 변환을 추가합니다.

   <!--<ClaimsTransformations>-->
       ...
       <ClaimsTransformation Id="CreateRandomUPNUserName" TransformationMethod="CreateRandomString">
           <InputParameters>
               <InputParameter Id="randomGeneratorType" DataType="string" Value="GUID" />
           </InputParameters>
           <OutputClaims>
               <OutputClaim ClaimTypeReferenceId="upnUserName" TransformationClaimType="outputClaim" />
           </OutputClaims>
       </ClaimsTransformation>
   
       <ClaimsTransformation Id="CreateAlternativeSecurityId" TransformationMethod="CreateAlternativeSecurityId">
           <InputClaims>
               <InputClaim ClaimTypeReferenceId="issuerUserId" TransformationClaimType="key" />
               <InputClaim ClaimTypeReferenceId="identityProvider" TransformationClaimType="identityProvider" />
           </InputClaims>
           <OutputClaims>
               <OutputClaim ClaimTypeReferenceId="alternativeSecurityId" TransformationClaimType="alternativeSecurityId" />
           </OutputClaims>
       </ClaimsTransformation>
       
       <ClaimsTransformation Id="CreateUserPrincipalName" TransformationMethod="FormatStringClaim">
           <InputClaims>
               <InputClaim ClaimTypeReferenceId="upnUserName" TransformationClaimType="inputClaim" />
           </InputClaims>
           <InputParameters>
               <InputParameter Id="stringFormat" DataType="string" Value="cpim_{0}@{RelyingPartyTenantId}" />
           </InputParameters>
           <OutputClaims>
               <OutputClaim ClaimTypeReferenceId="userPrincipalName" TransformationClaimType="outputClaim" />
           </OutputClaims>
       </ClaimsTransformation>
   <!--</ClaimsTransformations>-->

alternativeSecurityIduserPrincipalName 클레임에 대한 값을 생성하는 데 사용하는 세 가지 클레임 변환을 정의했습니다. 이러한 ClaimsTransformations는 3.3단계의 OAuth2 기술 프로필에서 호출됩니다.

3.3단계 - Facebook 클레임 공급자 구성

사용자가 Facebook 계정을 사용하여 로그인할 수 있도록 하려면 Azure AD B2C가 엔드포인트를 통해 통신할 수 있는 클레임 공급자로 계정을 정의해야 합니다. Facebook 계정을 클레임 공급자로 정의할 수 있습니다.

ContosoCustomPolicy.XML 파일에서 ClaimsProviders 요소를 찾고 다음 코드를 사용하여 새 클레임 공급자를 추가합니다.

    <!--<ClaimsProviders>-->
        ...
        <ClaimsProvider>
            <!-- The following Domain element allows this profile to be used if the request comes with domain_hint 
                    query string parameter, e.g. domain_hint=facebook.com  -->
            <Domain>facebook.com</Domain>
            <DisplayName>Facebook</DisplayName>
            <TechnicalProfiles>
                <TechnicalProfile Id="Facebook-OAUTH">
                <!-- The text in the following DisplayName element is shown to the user on the claims provider 
                        selection screen. -->
                <DisplayName>Facebook</DisplayName>
                <Protocol Name="OAuth2" />
                <Metadata>
                    <Item Key="ProviderName">facebook</Item>
                    <Item Key="authorization_endpoint">https://www.facebook.com/dialog/oauth</Item>
                    <Item Key="AccessTokenEndpoint">https://graph.facebook.com/oauth/access_token</Item>
                    <Item Key="HttpBinding">GET</Item>
                    <Item Key="UsePolicyInRedirectUri">0</Item>                
                    <Item Key="client_id">facebook-app-id</Item>
                    <Item Key="scope">email public_profile</Item>
                    <Item Key="ClaimsEndpoint">https://graph.facebook.com/me?fields=id,first_name,last_name,name,email</Item>
                    <Item Key="AccessTokenResponseFormat">json</Item>
                </Metadata>
                <CryptographicKeys>
                    <Key Id="client_secret" StorageReferenceId="facebook-policy-key" />
                </CryptographicKeys>
                <InputClaims />
                <OutputClaims>
                    <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="id" />
                    <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="first_name" />
                    <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="last_name" />
                    <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
                    <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
                    <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="facebook.com" AlwaysUseDefaultValue="true" />
                    <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" AlwaysUseDefaultValue="true" />
                </OutputClaims>
                <OutputClaimsTransformations>
                    <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
                    <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
                    <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
                </OutputClaimsTransformations>
                </TechnicalProfile>
            </TechnicalProfiles>
        </ClaimsProvider>
    <!--</ClaimsProviders>-->

다음을

  • 1단계에서 획득한 Facebook appID의 값을 갖는 facebook-app-id.
  • 2단계에서 획득한 Facebook 정책 키 이름을 갖는 facebook-policy-key

3.2단계OutputClaimsTransformations 컬렉션에 정의된 클레임 변환을 확인합니다.

3.4단계 - Microsoft Entra 기술 프로필 만들기

로컬 계정으로 로그인하는 것처럼 Microsoft Entra 스토리지에 연결하거나 사용자 소셜 계정을 저장하거나 읽는 데 사용하는 Microsoft Entra ID 기술 프로필을 구성해야 합니다.

  1. ContosoCustomPolicy.XML 파일에서 AAD-UserUpdate 기술 프로필을 찾은 후, 다음 코드를 사용하여 새 기술 프로필을 추가합니다.

        <TechnicalProfile Id="AAD-UserWriteUsingAlternativeSecurityId">
            <DisplayName>Azure Active Directory technical profile for handling social accounts</DisplayName>
            <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    
            <Metadata>
                <Item Key="Operation">Write</Item>
                <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
            </Metadata>        
    
            <CryptographicKeys>
                <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
            </CryptographicKeys>
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="alternativeSecurityId" PartnerClaimType="alternativeSecurityId" Required="true" />
            </InputClaims>
            <PersistedClaims>
                <!-- Required claims -->
                <PersistedClaim ClaimTypeReferenceId="alternativeSecurityId" />
                <PersistedClaim ClaimTypeReferenceId="userPrincipalName" />
                <PersistedClaim ClaimTypeReferenceId="mailNickName" DefaultValue="unknown" />
                <PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
    
                <!-- Optional claims -->
                <PersistedClaim ClaimTypeReferenceId="givenName" />
                <PersistedClaim ClaimTypeReferenceId="surname" />
            </PersistedClaims>
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="objectId" />
                <OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
            </OutputClaims>
    
        </TechnicalProfile>
    

    Microsoft Entra ID에 새로운 소셜 계정을 작성하는 새로운 Microsoft Entra 기술 프로필 AAD-UserWriteUsingAlternativeSecurityId를 추가했습니다.

  2. B2C_1A_TokenSigningKeyContainer서명 구성에서 만든 토큰 서명 키로 바꿉니다.

  3. ContosoCustomPolicy.XML 파일에서 다음 코드를 사용하여 AAD-UserWriteUsingAlternativeSecurityId 기술 프로필 뒤에 다른 Microsoft Entra 기술 프로필을 추가합니다.

       <TechnicalProfile Id="AAD-UserReadUsingAlternativeSecurityId">
           <DisplayName>Azure Active Directory</DisplayName>
           <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
           <Metadata>
               <Item Key="Operation">Read</Item>
               <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
           </Metadata>
           <CryptographicKeys>
               <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
               </CryptographicKeys>
           <InputClaims>
               <InputClaim ClaimTypeReferenceId="alternativeSecurityId" PartnerClaimType="alternativeSecurityId" Required="true" />
           </InputClaims>
           <OutputClaims>
               <!-- Required claims -->
               <OutputClaim ClaimTypeReferenceId="objectId" />
    
               <!-- Optional claims -->
               <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
               <OutputClaim ClaimTypeReferenceId="displayName" />
               <OutputClaim ClaimTypeReferenceId="givenName" />
               <OutputClaim ClaimTypeReferenceId="surname" />
           </OutputClaims>
       </TechnicalProfile>
    

    Microsoft Entra ID에서 새 소셜 계정을 읽는 새로운 Microsoft Entra 기술 프로필 AAD-UserReadUsingAlternativeSecurityId를 추가했습니다. alternativeSecurityId를 소셜 계정에 대한 고유 식별자로 사용합니다.

  4. B2C_1A_TokenSigningKeyContainer서명 구성에서 만든 토큰 서명 키로 바꿉니다.

3.5단계: 콘텐츠 정의 구성

사용자가 로그인한 후 자체 어설션된 기술 프로필을 사용하여 일부 정보를 수집할 수 있습니다. 따라서 자체 어설션된 기술 프로필에 대한 콘텐츠 정의를 구성해야 합니다.

ContosoCustomPolicy.XML 파일에서 ContentDefinitions 요소를 찾은 후, 다음 코드를 사용하여 ContentDefinitions 컬렉션에 새 콘텐츠 정의를 추가합니다.

    <ContentDefinition Id="socialAccountsignupContentDefinition">
        <LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri>
        <RecoveryUri>~/common/default_page_error.html</RecoveryUri>
        <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.7</DataUri>
        <Metadata>
            <Item Key="DisplayName">Collect information from user page alongside those from social Idp.</Item>
        </Metadata>
    </ContentDefinition>

이 콘텐츠 정의를 다음 단계(3.6단계)에서 자체 어설션된 기술 프로필의 메타데이터로 사용합니다.

3.6단계 - 자체 어설션된 기술 프로필 구성

이 단계에서 구성하는 자체 어설션된 기술 프로필은 사용자로부터 자세한 정보를 수집하거나 소셜 계정에서 얻은 유사한 정보를 업데이트하는 데 사용됩니다.

ContosoCustomPolicy.XML 파일에서 ClaimsProviders 섹션을 찾은 후, 다음 코드를 사용하여 새 클레임 공급자를 추가합니다.

    <!--<ClaimsProviders>-->
        ...
        <ClaimsProvider>
            <DisplayName>Self Asserted for social sign in</DisplayName>
            <TechnicalProfiles>
                <TechnicalProfile Id="SelfAsserted-Social">
                    <DisplayName>Collect more info during social signup</DisplayName>
                    <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
                    <Metadata>
                      <Item Key="ContentDefinitionReferenceId">socialAccountsignupContentDefinition</Item>
                    </Metadata>
                    <CryptographicKeys>
                      <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
                    </CryptographicKeys>
                    <InputClaims>
                      <!-- These claims ensure that any values retrieved in the previous steps (e.g. from an external IDP) are prefilled. 
                           Note that some of these claims may not have any value, for example, if the external IDP did not provide any of
                           these values, or if the claim did not appear in the OutputClaims section of the IDP.
                           In addition, if a claim is not in the InputClaims section, but it is in the OutputClaims section, then its
                           value will not be prefilled, but the user will still be prompted for it (with an empty value). -->
                      <InputClaim ClaimTypeReferenceId="displayName" />
                      <InputClaim ClaimTypeReferenceId="givenName" />
                      <InputClaim ClaimTypeReferenceId="surname" />
                    </InputClaims>
                    <!---User will be asked to input or update these values-->
                    <DisplayClaims>
                        <DisplayClaim ClaimTypeReferenceId="displayName"/>
                        <DisplayClaim ClaimTypeReferenceId="givenName"/>
                        <DisplayClaim ClaimTypeReferenceId="surname"/>
                    </DisplayClaims>

                    <OutputClaims>
                      <!-- These claims are not shown to the user because their value is obtained through the "ValidationTechnicalProfiles"
                           referenced below, or a default value is assigned to the claim. A claim is only shown to the user to provide a 
                           value if its value cannot be obtained through any other means. -->
                      <OutputClaim ClaimTypeReferenceId="objectId" />
                      <OutputClaim ClaimTypeReferenceId="newUser" />
                      <!---<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />-->
          
                      <!-- Optional claims. These claims are collected from the user and can be modified. If a claim is to be persisted in the directory after having been 
                           collected from the user, it needs to be added as a PersistedClaim in the ValidationTechnicalProfile referenced below, i.e. 
                           in AAD-UserWriteUsingAlternativeSecurityId. -->
                      <OutputClaim ClaimTypeReferenceId="displayName" />
                      <OutputClaim ClaimTypeReferenceId="givenName" />
                      <OutputClaim ClaimTypeReferenceId="surname" />
                    </OutputClaims>
                    <ValidationTechnicalProfiles>
                      <ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
                    </ValidationTechnicalProfiles>
                  </TechnicalProfile>
            </TechnicalProfiles>
        </ClaimsProvider>
    <!--</ClaimsProviders>-->

추가한 클레임 공급자에는 자체 어설션된 기술 프로필인 SelfAsserted-Social이 포함되어 있습니다. 자체 어설션 기술 프로필은 AAD-UserWriteUsingAlternativeSecurityId 기술 프로필을 유효성 검사 기술 프로필로 사용합니다. 따라서 사용자가 계속 단추를 선택하면 AAD-UserWriteUsingAlternativeSecurityId 기술 프로필이 실행됩니다(7단계의 스크린샷 참조).

또한 메타데이터 섹션의 3.5단계에서 구성한 콘텐츠 정의인 socialAccountsignupContentDefinition을 추가했습니다.

4단계 - 사용자 경험 오케스트레이션 단계 업데이트

ContosoCustomPolicy.XML 파일에서 HelloWorldJourney 사용자 경험을 찾고 모든 오케스트레이션 단계를 다음 코드에 표시된 단계로 바꿉니다.

    <!--<OrchestrationSteps>-->
        ...
        <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp">
            <ClaimsProviderSelections>
                <ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
            </ClaimsProviderSelections>
        </OrchestrationStep>
    
        <OrchestrationStep Order="2" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="FacebookExchange"
                    TechnicalProfileReferenceId="Facebook-OAUTH" />
            </ClaimsExchanges>
        </OrchestrationStep>
    
        <!-- For social IDP authentication, attempt to find the user account in the
        directory. -->
        <OrchestrationStep Order="3" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId" />
            </ClaimsExchanges>
        </OrchestrationStep>
    
        <!-- Show self-asserted page only if the directory does not have the user account
        already (i.e. we don't have an objectId).  -->
        <OrchestrationStep Order="4" Type="ClaimsExchange">
            <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                    <Value>objectId</Value>
                    <Action>SkipThisOrchestrationStep</Action>
                </Precondition>
            </Preconditions>
            <ClaimsExchanges>
                <ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social" />
            </ClaimsExchanges>
        </OrchestrationStep>
    
        <OrchestrationStep Order="5" Type="ClaimsExchange">
            <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                    <Value>objectId</Value>
                    <Action>SkipThisOrchestrationStep</Action>
                </Precondition>
            </Preconditions>
            <ClaimsExchanges>
                <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
            </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
    <!--</OrchestrationSteps>-->

오케스트레이션에서는 사용자가 소셜 계정을 사용하여 로그인할 수 있도록 하는 기술 프로필을 참조했습니다.

사용자 지정 정책이 실행되는 경우:

  • 오케스트레이션 1단계 - 이 단계에는 사용자가 선택할 수 있는 사용 가능한 로그인 옵션을 나열하는 ClaimsProviderSelections 요소가 포함되어 있습니다. 이 경우 한 가지 옵션인 FacebookExchange만 있으므로 정책이 실행되면 TargetClaimsExchangeId 특성에 표시된 대로 사용자가 2단계의 Facebook.com으로 바로 이동됩니다.

  • 오케스트레이션 2단계 - Facebook-OAUTH 기술 프로필이 실행되므로 사용자가 로그인하기 위해 Facebook으로 리디렉션됩니다.

  • 오케스트레이션 3단계 - 3단계에서는 AAD-UserReadUsingAlternativeSecurityId 기술 프로필이 실행되어 Microsoft Entra ID 스토리지에서 사용자 소셜 계정을 읽으려고 시도합니다. 해당 소셜 계정을 찾으면 objectId가 출력 클레임으로 반환됩니다.

  • 오케스트레이션 4단계 - 이 단계는 사용자가 존재하지 않는 경우 실행됩니다(objectId가 존재하지 않음). 사용자로부터 추가 정보를 수집하거나 소셜 계정에서 얻은 유사한 정보를 업데이트하는 양식을 보여 줍니다.

  • 오케스트레이션 5단계 - 이 단계는 사용자가 아직 존재하지 않는 경우(objectId가 존재하지 않음) 실행되므로 AAD-UserWriteUsingAlternativeSecurityId 기술 프로필이 실행되어 소셜 계정을 Microsoft Entra ID에 기록합니다.

  • 오케스트레이션 6단계 - 마지막으로 6단계는 정책 실행이 끝날 때 JWT 토큰을 조합하고 반환합니다.

5단계 - 신뢰 당사자 출력 클레임 업데이트

ContosoCustomPolicy.XML 파일에서 RelyingParty 요소를 찾은 다음, 모든 출력 클레임 컬렉션을 다음 코드로 바꿉니다.

    <OutputClaim ClaimTypeReferenceId="displayName" />
    <OutputClaim ClaimTypeReferenceId="givenName" />
    <OutputClaim ClaimTypeReferenceId="surname" />
    <OutputClaim ClaimTypeReferenceId="email" />
    <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
    <OutputClaim ClaimTypeReferenceId="identityProvider" />

ID 공급자(identityProvider)를 출력 클레임으로 추가했으므로 신뢰 당사자 애플리케이션에 반환된 JWT 토큰에 포함됩니다.

6단계 - 정책 업로드

정책 파일을 업로드하려면 사용자 지정 정책 파일 업로드의 단계를 따릅니다. 이미 포털에 있는 파일과 이름이 같은 파일을 업로드하면 사용자 지정 정책이 이미 있는 경우 덮어쓰기를 선택해야 합니다.

7단계 - 정책 테스트

사용자 지정 정책을 테스트하려면 사용자 지정 정책 테스트의 단계를 따릅니다.

Facebook 로그인 페이지로 리디렉션됩니다. Facebook 자격 증명을 입력한 다음, 로그인을 선택합니다. 선택할 수 있는 여러 가지 로그인 옵션이 없기 때문에 오케스트레이션 단계에서 설정하면 Facebook으로 직접 리디렉션됩니다. 일반적으로 앱에서는 선택할 경우 정책이 실행되는 Facebook으로 로그인과 같은 단추를 추가했습니다.

이 정책을 처음 실행하는 경우(소셜 계정이 Microsoft Entra 스토리지에 아직 없음) 아래와 같은 스크린샷이 표시됩니다. 후속 정책 실행 시에는 소셜 계정이 Microsoft Entra 스토리지에 이미 있으므로 이 화면이 표시되지 않습니다.

Screenshot of sign-in flow with social account.

표시 이름, 이름을 입력하거나 업데이트한 다음, 계속 단추를 선택합니다.

정책 실행이 완료되면 https://jwt.ms로 리디렉션되고 디코딩된 JWT 토큰이 표시됩니다. 다음 JWT 토큰 코드 조각과 유사합니다.

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "pxLOMWFgP4T..."
}.{
   ...
  "acr": "b2c_1a_contosocustompolicy",
   ...
  "given_name": "Maurice",
  "family_name": "Paulet",
  "name": "Maurice Paulet",
  "email": "maurice.p@contoso.com",
  "idp": "facebook.com"
}.[Signature]

ID 공급자 "idp": "facebook.com"은 JWT 토큰에 포함되어 있습니다.

결합된 로컬 및 소셜 로그인

이 문서에서 사용자 경험 오케스트레이션 단계는 사용자가 소셜 계정을 사용하여 로그인할 수 있도록 하는 기술 프로필만 참조합니다. 사용자가 로컬 계정 또는 소셜 계정을 사용하여 로그인할 수 있도록 오케스트레이션 단계를 수정할 수 있습니다. 이를 위해 첫 번째 오케스트레이션 단계의 ClaimsProviderSelections 요소는 사용자가 사용할 수 있는 로그인 옵션을 나열합니다.

다음 단계를 사용하여 결합된 로컬 및 소셜 계정을 추가합니다.

  1. ContosoCustomPolicy.XML 파일에서 AccountTypeInputCollector 자체 어설션된 기술 프로필을 찾고, 다음 코드를 사용하여 출력 클레임 컬렉션에 authenticationSource 클레임을 추가합니다.

        <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localIdpAuthentication" AlwaysUseDefaultValue="true" />
    
  2. UserJourneys 섹션에서 다음 코드를 사용하여 새 사용자 경험인 LocalAndSocialSignInAndSignUp을 추가합니다.

        <!--<UserJourneys>-->
            ...
            <UserJourney Id="LocalAndSocialSignInAndSignUp">
                <OrchestrationSteps>
                    <!--Orchestration steps will be added here-->
                </OrchestrationSteps>
            </UserJourney>
        <!--</UserJourneys>-->
    
  3. 사용자가 만든 사용자 경험인 LocalAndSocialSignInAndSignUp에서 다음 코드를 사용하여 오케스트레이션 단계를 추가합니다.

        <!--<UserJourneys>
            ...
            <UserJourney Id="LocalAndSocialSignInAndSignUp">
                <OrchestrationSteps>-->
                <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="SignupOrSigninContentDefinition">
                    <ClaimsProviderSelections>
                      <ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
                      <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
                    </ClaimsProviderSelections>
                    <ClaimsExchanges>
                      <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="UserSignInCollector" />
                    </ClaimsExchanges>
                </OrchestrationStep>
                <!-- Check if the user has selected to sign in using one of the social providers -->
                <OrchestrationStep Order="2" Type="ClaimsExchange">
                    <Preconditions>
                        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                            <Value>objectId</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                    </Preconditions>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAUTH" />
                        <ClaimsExchange Id="AccountTypeInputCollectorClaimsExchange" TechnicalProfileReferenceId="AccountTypeInputCollector"/>
                    </ClaimsExchanges>
                </OrchestrationStep>
    
                <!--For Local sign in option start-->
    
                <OrchestrationStep Order="3" Type="ClaimsExchange">
                    <Preconditions>
                        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                            <Value>objectId</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                          <Value>accountType</Value>
                          <Value>work</Value>
                          <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                            <Value>authenticationSource</Value>
                            <Value>socialIdpAuthentication</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                    </Preconditions>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="GetAccessCodeClaimsExchange" TechnicalProfileReferenceId="AccessCodeInputCollector" />
                    </ClaimsExchanges>
                </OrchestrationStep>
    
                <OrchestrationStep Order="4" Type="ClaimsExchange">
                    <Preconditions>
                        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                            <Value>objectId</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                            <Value>authenticationSource</Value>
                            <Value>socialIdpAuthentication</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                    </Preconditions>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="UserInformationCollector" />
                    </ClaimsExchanges>
                </OrchestrationStep>  
    
                <OrchestrationStep Order="5" Type="ClaimsExchange">
                    <Preconditions>
                        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                            <Value>authenticationSource</Value>
                            <Value>socialIdpAuthentication</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                    </Preconditions>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="AADUserReaderExchange" TechnicalProfileReferenceId="AAD-UserRead"/>
                    </ClaimsExchanges>
                </OrchestrationStep>                
                <!--For Local sign in option end-->
    
                <!--For social sign in option start-->
                <!-- For social IDP authentication, attempt to find the user account in the
                directory. -->
                <OrchestrationStep Order="6" Type="ClaimsExchange">
                   <Preconditions>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                        <Value>authenticationSource</Value>
                        <Value>localIdpAuthentication</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                   </Preconditions>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId" />
                    </ClaimsExchanges>
                </OrchestrationStep>
    
                <!-- Show self-asserted page only if the directory does not have the user account
                already (i.e. we do not have an objectId).  -->
                <OrchestrationStep Order="7" Type="ClaimsExchange">
                    <Preconditions>
                        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                            <Value>objectId</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                            <Value>authenticationSource</Value>
                            <Value>localIdpAuthentication</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                    </Preconditions>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social" />
                    </ClaimsExchanges>
                </OrchestrationStep>
    
                <OrchestrationStep Order="8" Type="ClaimsExchange">
                    <Preconditions>
                        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                            <Value>objectId</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                            <Value>authenticationSource</Value>
                            <Value>localIdpAuthentication</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                    </Preconditions>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
                    </ClaimsExchanges>
                </OrchestrationStep>
                <!--For social sign in option end-->
                <OrchestrationStep Order="9" Type="ClaimsExchange">
                    <ClaimsExchanges>
                    <ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="UserInputMessageClaimGenerator"/>
                    </ClaimsExchanges>          
                </OrchestrationStep>
    
                <OrchestrationStep Order="10" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
               <!-- </OrchestrationSteps>
            </UserJourney>
        </UserJourneys>-->
    

    첫 번째 단계에서는 사용자가 경험, 로컬 또는 소셜 인증에서 선택해야 하는 옵션을 지정합니다. 다음 단계에서는 사전 조건을 사용하여 사용자가 선택한 옵션 또는 사용자의 현재 경험 단계를 추적합니다. 예를 들어 authenticationSource 클레임을 사용하여 로컬 인증 경험과 소셜 인증 경험을 구분합니다.

  4. RelyingParty 섹션에서 DefaultUserJourney ReferenceIdLocalAndSocialSignInAndSignUp으로 변경합니다.

  5. 6단계7단계의 절차를 사용하여 정책을 업로드하고 실행합니다. 정책을 실행하면 다음 스크린샷과 유사한 화면이 표시됩니다.

    A screenshot of combined local and social sign-up or sign-in interface.

    사용자가 로컬 계정 또는 소셜 계정을 사용하여 등록하거나 로그인할 수 있음을 확인할 수 있습니다.

다음 단계