La historia de cómo configuré Azure AD B2C en React and React Native Part 2 (Tutorial)

imagen

Prefacio


Continuación del ciclo de trabajo con Azure B2C. En este artículo hablaré sobre el punto más difícil y no obvio, a saber, el Marco de experiencia de identidad.

El objetivo principal es armar una imagen para aquellos que no están en absoluto en el tema y ayudar a configurar algunas características básicas.

Enlaces a publicaciones relacionadas


Configuración básica


Antes de comenzar la configuración básica, me gustaría decirle cómo ocurre el proceso de cargar nuevas reglas:

  1. Ir al marco de Identity Experience
  2. Haga clic en enviar política de usuario
  3. Seleccione un archivo (no olvide hacer clic en "Sobrescribir política personalizada, si ya existe")
  4. Nosotros enviamos

imagen

De hecho, nada ha cambiado desde la última vez, PERO:
Si cambia el archivo TrustFrameworkExtension.xml o TrustFrameworkBase.xml , descargue periódicamente el archivo que se refiere a ellos.
A veces, cuando realiza cambios en uno de estos archivos, prueba, sucede que sus cambios no aparecen. Esto se debe al hecho de que
ha cambiado algo en el archivo base para que durante la verificación el archivo secundario produzca un error.

En el último artículo, nos decidimos por el hecho de que agregamos los siguientes archivos:
a.TrustFrameworkBase.xml
b.TrustFrameworkExtensions.xml
c.SignUpOrSignin. XML
d.ProfileEdit. XML
e.PasswordReset. XML

Ahora me gustaría contar en detalle sobre cada uno de ellos.

TrustFrameworkBase.xml

Este archivo contiene la configuración básica. De hecho, es la base de los conceptos básicos, pero en los tutoriales dicen "Mejor no tocar este archivo". Esto es en parte cierto, pero hay algunos puntos de los que no se habla:

  1. Cualquier tutorial que diga realizar cambios en TrustFrameworkExtensions.xml esencialmente reescribe las reglas de TrustFrameworkBase.xml
  2. Hay situaciones en las que es más conveniente cambiar algo en TrustFrameworkBase.xml .
  3. Si encuentra en otros archivos un enlace a un objeto que no está en estos archivos, entonces se encuentra 100% en TrustFrameworkBase.xml y puede abrirlo y ver

Desde mi experiencia, diré: cambié solo dos cosas en este archivo (Localización y eliminé un campo).

TrustFrameworkExtension.xml

Con este archivo pasarán mucho tiempo juntos. De hecho, este es el archivo principal para su configuración. Lo mencionan constantemente en tutoriales.

SignUpOrSignin. XML, ProfileEdit. XML, PasswordReset. XML

Estos archivos son páginas de hoja. Probablemente quieras agregar el tuyo. Tendrán la menor cantidad de cambio.

Ahora hablemos de la estructura del archivo. Todos los archivos tienen una estructura similar, por lo que lo describiré sobre la base del archivo TrustFrameworkExtension.xml .

El archivo está dividido en varios bloques principales.

<TrustFrameworkPolicy>
  <BasePolicy> <!--     -->
      <TenantId>customtenant.onmicrosoft.com</TenantId>
      <PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
  </BasePolicy>

  <BuildingBlocks> <!--       UI -->
  </BuildingBlocks>

  <ClaimsProviders> <!--        JWT token) -->
  </ClaimsProviders>
  
  <UserJourneys> <!--       -->
  </UserJourneys>
</TrustFrameworkPolicy>

Ahora sobre cada bloque por separado.

Bloques de construcción


En este bloque agregamos "herramientas" que podemos usar en futuros trabajos.

ClaimsSchema

elemento ClaimsSchema determina los tipos de declaraciones, que pueden ser referenciados dentro de la política.

  <BuildingBlocks>
    <ClaimsSchema>
      <ClaimType Id="picture"><!--      UI     -->
        <DisplayName>Picture</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="country"><!--     -->
        <DisplayName>Country</DisplayName>
        <DataType>string</DataType>
        <UserInputType>DropdownSingleSelect</UserInputType>
        <Restriction>
          <Enumeration Text="Russia" Value="russia" SelectByDefault="false" />
          <Enumeration Text="Other" Value="other" SelectByDefault="false" />
        </Restriction>
      </ClaimType>
           ...
    </ClaimsSchema>
  

Predicados Los

predicados y los elementos de validación de predicados permiten la validación para garantizar que solo se ingresen datos formados correctamente en el cliente Azure Active Directory B2C (Azure AD B2C).

    <Predicates> <!--     ,       -->
      <Predicate Id="LengthRange" Method="IsLengthRange">
        <UserHelpText>The password must be between 6 and 64 characters.</UserHelpText>
        <Parameters>
          <Parameter Id="Minimum">6</Parameter>
          <Parameter Id="Maximum">64</Parameter>
        </Parameters>
      </Predicate>
      <Predicate Id="Lowercase" Method="IncludesCharacters">
        <UserHelpText>a lowercase letter</UserHelpText>
        <Parameters>
          <Parameter Id="CharacterSet">a-z</Parameter>
        </Parameters>
      </Predicate>
          ...
    </Predicates>
  

PredicateValidations

Mientras que los predicados determinan si un tipo de aserción está validado, PredicateValidations agrupa un conjunto de predicados para formar una verificación de entrada del usuario que coincida con el tipo de aserción.

    <PredicateValidations> <!--       -->
      <PredicateValidation Id="CustomPassword">
        <PredicateGroups>
          <PredicateGroup Id="LengthGroup">
            <PredicateReferences MatchAtLeast="1">
              <PredicateReference Id="LengthRange" />
            </PredicateReferences>
          </PredicateGroup>
          <PredicateGroup Id="CharacterClasses">
            <UserHelpText>The password must have at least 1 of the following:</UserHelpText>
            <PredicateReferences MatchAtLeast="2">
              <PredicateReference Id="Lowercase" /> <!--   ,    -->
              <PredicateReference Id="Uppercase" />
                    ...
            </PredicateReferences>
          </PredicateGroup>
        </PredicateGroups>
      </PredicateValidation>
    </PredicateValidations>
  

ClaimsTransformations

elemento ClaimsTransformations contiene una lista de funciones de transformación de las afirmaciones que se pueden utilizar en el modo de interacción del usuario como parte de una política personalizada.

    <ClaimsTransformations> <!--      -->
      <ClaimsTransformation Id="GenerateSendGridRequestBody" TransformationMethod="GenerateJson">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="personalizations.0.to.0.email" />
          <InputClaim ClaimTypeReferenceId="otp" TransformationClaimType="personalizations.0.dynamic_template_data.otp" />
          <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="personalizations.0.dynamic_template_data.email" />
        </InputClaims>
        <InputParameters>
          <InputParameter Id="template_id" DataType="string" Value="d-b0000000000000000000000000000000" /> <!-- Template ID SendGrid (    ) -->
          <InputParameter Id="from.email" DataType="string" Value="custom@email.com" />
          <InputParameter Id="personalizations.0.dynamic_template_data.subject" DataType="string" Value="Welcome to Habr!"/>
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="sendGridReqBody" TransformationClaimType="outputClaim" />
        </OutputClaims>
      </ClaimsTransformation>
            ...
    </ClaimsTransformations>
  

ContentDefinitions

Le permite definir plantillas para cada una de sus páginas.

    <ContentDefinitions> <!--         -->
      <ContentDefinition Id="api.signuporsignin">
        <LoadUri>https://azure.blob.core.windows.net/yourblobstorage/pagelayoutfile.html</LoadUri>
        <RecoveryUri>~/common/default_page_error.html</RecoveryUri>
        <DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:1.2.0</DataUri>
      </ContentDefinition>
          ...
    </ContentDefinitions>
  

DisplayControls

El control Display es un elemento de interfaz de usuario que tiene características especiales e interactúa con el servicio del servidor Azure Active Directory B2C (Azure AD B2C)

    <DisplayControls> <!--      -->
      <DisplayControl Id="emailVerificationControl" UserInterfaceControlType="VerificationControl">
        <DisplayClaims> <!--   -->
          <DisplayClaim ClaimTypeReferenceId="email" Required="true" />
          <DisplayClaim ClaimTypeReferenceId="verificationCode" ControlClaimType="VerificationCode" Required="true" />
        </DisplayClaims>
        <OutputClaims> <!--   (     ) -->
          <OutputClaim ClaimTypeReferenceId="email" />
        </OutputClaims>
        <Actions>
          <Action Id="SendCode"> <!--        -->
            <ValidationClaimsExchange>
              <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="GenerateOtp" />
              <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="SendGrid" />
            </ValidationClaimsExchange>
          </Action>
            ...
        </Actions>
      </DisplayControl>
          ...
    </DisplayControls>
  </BuildingBlocks>

Proveedores de reclamos


En este bloque, crearemos las páginas ellos mismos, o más bien su contenido. Aquí indicaremos qué datos tiene la página de entrada y salida.

ClaimsProvider vincula los perfiles técnicos al proveedor de reclamos.

  <ClaimsProviders>
    <ClaimsProvider> <!--   -          -->
      <DisplayName>Self Asserted</DisplayName>
    

El elemento TechnicalProfiles contiene un conjunto de perfiles técnicos compatibles con el proveedor de reclamos.

      <TechnicalProfiles>
        <TechnicalProfile Id="SelfAsserted-Social">
          <DisplayName>User ID 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">api.selfasserted</Item> <!--  . (        ,   )-->
          </Metadata>
          <CryptographicKeys>
            <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" /> <!--       -->
          </CryptographicKeys>
          <InputClaims> <!--   ..          -->
            <InputClaim ClaimTypeReferenceId="givenName" />
            <InputClaim ClaimTypeReferenceId="surname" />
          </InputClaims>
          <OutputClaims> <!--  .       ,      (   ) -->
              <!-- 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). -->
            <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="givenName" Required="true"/>
            <OutputClaim ClaimTypeReferenceId="surname" Required="true"/>
            <OutputClaim ClaimTypeReferenceId="country" Required="true"/>
          </OutputClaims>
        </TechnicalProfile>
      </ClaimsProvider>
      

Ejemplo de agregar proveedores de identidad de Facebook


    <ClaimsProvider> <!--    .       -->
      <DisplayName>Facebook</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="Facebook-OAUTH">
          <Metadata>
            <Item Key="client_id">FACEBOOK_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,picture</Item>
          </Metadata>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="picture" PartnerClaimType="picture" />
          </OutputClaims>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
  

TrustFrameworkBase.xml

      <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>
  
              <!-- The Facebook required HTTP GET method, but the access token response is in JSON format from 3/27/2017 -->
              <Item Key="AccessTokenResponseFormat">json</Item>
            </Metadata>
            <CryptographicKeys>
              <Key Id="client_secret" StorageReferenceId="B2C_1A_FacebookSecret" />
            </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>
            <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
          </TechnicalProfile>
        </TechnicalProfiles>
      </ClaimsProvider>


Viajes de usuario


Los UserJourneys del usuario indican rutas explícitas a través de las cuales la política permite que la aplicación basada en reclamos proporcione al usuario los reclamos requeridos.

A continuación agregué un par de cosas simples, el resto es fácil de encontrar en los tutoriales que agregaré a continuación.

  <UserJourneys>
    <UserJourney Id="SignUp"> <!--  ID UserJourney.       ,     TrustFrameworkExtension.xml-->
      <OrchestrationSteps><!--  .   -->
        <OrchestrationStep Order="1" Type="ClaimsExchange" ContentDefinitionReferenceId="api.localaccountsignup">
          <ClaimsExchanges> <!--       TechnicalProfileReferenceId. Id   ,       -->
            <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail-2" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> <!--     -->
      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>
    <UserJourney Id="PasswordReset">
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="PasswordResetUsingEmailAddressExchange" TechnicalProfileReferenceId="LocalAccountDiscoveryUsingEmailAddress" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>
       ...
  </UserJourneys>

Ejemplo de intercambio de ClaimsExchange
ClaimsExchanges .

    <ClaimsProviderSelections>
      <ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
      <ClaimsProviderSelection TargetClaimsExchangeId="GoogleExchange" />
      <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
    </ClaimsProviderSelections>
    <ClaimsExchanges>
      <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
    </ClaimsExchanges>
  


Tareas tipicas


Como resultado de lo anterior, le será más fácil comprender los tutoriales a continuación.


SignUpOrSignin.XML, ProfileEdit.XML, PasswordReset.XML


Estos son los archivos finales donde puede sobrescribir \ agregar BuildingBlocks y donde indicamos qué datos agregar al token.

  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" PolicySchemaVersion="0.3.0.0" TenantId="antekesd.onmicrosoft.com" PolicyId="B2C_1A_signup_signin" PublicPolicyUri="http://antekesd.onmicrosoft.com/B2C_1A_signup_signin">

  <BasePolicy>
    <TenantId>antekesd.onmicrosoft.com</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
  </BasePolicy>
  <BuildingBlocks>
    <ContentDefinitions>
      <ContentDefinition Id="api.signuporsignin"> <!--        -->
        <LoadUri>https://some.blob.core.windows.net/some/some.html</LoadUri>
        <RecoveryUri>~/common/default_page_error.html</RecoveryUri>
        <DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:1.2.0</DataUri>
      </ContentDefinition>
    </ContentDefinitions>
  </BuildingBlocks>
  <RelyingParty>
    <DefaultUserJourney ReferenceId="SignUpOrSignIn" /> <!--  ,     -->
    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <OutputClaims> <!--    JWT Token.        -->
        <OutputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="email"/>
        <OutputClaim ClaimTypeReferenceId="givenName" Required="true"/>
        <OutputClaim ClaimTypeReferenceId="surname" Required="true"/>
        <OutputClaim ClaimTypeReferenceId="email" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
        <OutputClaim ClaimTypeReferenceId="identityProvider" />
        <OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
        <OutputClaim ClaimTypeReferenceId="picture" />
        <OutputClaim ClaimTypeReferenceId="country" Required="true"/>
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>
  </RelyingParty>
</TrustFrameworkPolicy>

Pruebas


Para probar los últimos cambios que necesita:

  1. Ir al marco de Identity Experience
  2. Seleccione la política que desea probar.
  3. Haga clic en "Ejecutar ahora"

imagen

Conclusión


Como resultado, recibirá un formulario de autorización que cumpla completamente (o casi) con los requisitos de su cliente.

¡Gracias por la atención!

All Articles