O conto de como eu configurei o Azure AD B2C em React e React Native Part 2 (Tutorial)

imagem

Prefácio


Continuação do ciclo de trabalho com o Azure B2C. Neste artigo, falarei sobre o ponto mais difícil e não óbvio, a saber, o Identity Experience Framework.

O objetivo principal é montar uma imagem para aqueles que não estão no assunto e ajudar a configurar alguns recursos básicos.

Links para posts relacionados


Configuração básica


Antes de iniciar a configuração básica, gostaria de dizer como ocorre o processo de carregamento de novas regras:

  1. Vá para o Identity Experience Framework
  2. Clique em enviar política do usuário
  3. Selecione um arquivo (não se esqueça de clicar em "Substituir política personalizada, se ela já existir")
  4. Nós enviamos

imagem

De fato, nada mudou desde a última vez, MAS:
Se você alterar o arquivo TrustFrameworkExtension.xml ou TrustFrameworkBase.xml - faça o download periódico do arquivo que se refere a eles.
Às vezes, quando você faz alterações em um desses arquivos, você testa, acontece que suas alterações não aparecem. Isso se deve ao fato de
você ter alterado algo no arquivo base para que durante a verificação o arquivo filho resulte em erro.

No último artigo, decidimos que adicionamos os seguintes arquivos:
a.TrustFrameworkBase.xml
b.TrustFrameworkExtensions.xml
c.SignUpOrSignin. XML
d.ProfileEdit. XML
e.PasswordReset. XML

Agora eu gostaria de contar em detalhes sobre cada um deles.

TrustFrameworkBase.xml

Este arquivo contém a configuração básica. De fato, é a base do básico, mas nos tutoriais eles costumam dizer "É melhor não tocar neste arquivo". Isso é parcialmente verdade, mas há alguns pontos que não são discutidos:

  1. Qualquer tutorial que diz para fazer alterações no TrustFrameworkExtensions.xml basicamente reescreve as regras do TrustFrameworkBase.xml
  2. Há situações em que é mais conveniente alterar algo no TrustFrameworkBase.xml .
  3. Se você encontrar em outros arquivos um link para um objeto que não esteja nesses arquivos, ele estará 100% no TrustFrameworkBase.xml e poderá abri-lo e ver

De acordo com minha experiência, alterei apenas duas coisas neste arquivo (localização e excluí um campo).

TrustFrameworkExtension.xml

Com esse arquivo, você passa muito tempo juntos. De fato, este é o arquivo principal para suas configurações. Ele é constantemente mencionado em tutoriais.

SignUpOrSignin. XML, ProfileEdit. XML, PasswordReset. XML

Esses arquivos são páginas de folha. Você provavelmente deseja adicionar o seu. Eles terão a menor quantidade de alteração.

Agora vamos falar sobre a estrutura do arquivo. Todos os arquivos têm uma estrutura semelhante, por isso vou descrevê-lo com base no arquivo TrustFrameworkExtension.xml .

O arquivo é dividido em vários blocos principais

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

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

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

Agora, sobre cada bloco separadamente.

Blocos de construção


Neste bloco, adicionamos "ferramentas" que podemos usar em trabalhos futuros.

ClaimsSchema

elemento ClaimsSchema determina os tipos de declarações, que podem ser referenciados dentro da 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

Predicados e elementos de validação de predicado permitem a validação para garantir que apenas dados formados corretamente sejam inseridos no cliente do 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

Enquanto os predicados determinam se um tipo de asserção é validado, PredicateValidations agrupa um conjunto de predicados para formar uma verificação de entrada do usuário que corresponda ao tipo de asserção.

    <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 contém uma lista de funções afirmações de transformação que podem ser usados na forma de interação do usuário, como parte de uma 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>
  

Definições de conteúdo

Permite definir modelos para cada uma das suas 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

O controle Display é um elemento da interface do usuário que possui recursos especiais e interage com o serviço do 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>

ClaimProviders


Neste bloco, criaremos as próprias páginas, ou melhor, o seu conteúdo. Aqui, indicaremos o que a página possui dados de entrada e saída.

ClaimsProvider vincula perfis técnicos ao provedor de declarações.

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

O elemento TechnicalProfiles contém um conjunto de perfis técnicos suportados pelo provedor de declarações.

      <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>
      

Exemplo de adição de provedores de identidade do 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>


Viagens do usuário


As jornadas do usuário do usuário indicam caminhos explícitos pelos quais a política permite que o aplicativo baseado em declarações forneça ao usuário as reivindicações necessárias.

Abaixo, adicionei algumas coisas simples, o resto é fácil de encontrar nos tutoriais que adicionarei abaixo.

  <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>

Exemplo de Troca de Declarações de Troca
ClaimsExchanges .

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


Tarefas típicas


Como resultado do exposto, será mais fácil para você entender os tutoriais abaixo.


SignUpOrSignin.XML, ProfileEdit.XML, PasswordReset.XML


Esses são os arquivos finais nos quais você pode sobrescrever \ add BuildingBlocks e onde indicamos quais dados adicionar ao 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>

Teste


Para testar as alterações mais recentes, você precisa:

  1. Vá para o Identity Experience Framework
  2. Selecione a política que você deseja testar.
  3. Clique em "Executar agora"

imagem

Conclusão


Como resultado, você receberá um formulário de autorização que atende totalmente (ou quase) aos requisitos do seu / cliente.

Obrigado pela atenção!

All Articles