Compartilhar via


Validar entradas de usuário usando a política personalizada do Azure Active Directory B2C

A política personalizada do Azure Active Directory B2C (Azure AD B2C) não só permite tornar obrigatórias as entradas de usuário, mas também validá-las. Você pode marcar entradas como obrigatório, como <DisplayClaim ClaimTypeReferenceId="givenName" Required="true"/>, mas isso não significa que os usuários inserirão dados válidos. O Azure AD B2C fornece várias maneiras de validar uma entrada de usuário. Neste artigo, você aprenderá a escrever uma política personalizada que coleta as entradas de usuário e as validas usando as seguintes abordagens:

  • Restrinja os dados que um usuário insere fornecendo uma lista de opções. Essa abordagem usa valores enumerados, que você adiciona ao fazer uma declaração.

  • Defina um padrão que uma entrada de usuário deve corresponder. Essa abordagem usa expressões regulares, que você adiciona ao fazer uma declaração.

  • Defina um conjunto de regras e exija que uma entrada de usuário obedeça a uma ou mais das regras. Essa abordagem usa predicados, que você adiciona ao fazer uma declaração.

  • Use o tipo de declaração especial reenterPassword para validar se o usuário reinseriu corretamente a senha durante a coleta da entrada de usuário.

  • Configure um perfil técnico de validação que defina regras de negócios complexas que não são possíveis de definir no nível da declaração. Por exemplo, você coleta uma entrada de usuário que precisa ser validada em relação a um valor ou um conjunto de valores em outra declaração.

Pré-requisitos

Observação

Este artigo faz parte da série de guias de instruções Criar e executar suas próprias políticas personalizadas no Azure Active Directory B2C. Recomendamos que você comece essa série com o primeiro artigo.

Etapa 1 – Validar a entrada de usuário limitando as opções de entrada de usuário

Se você souber todos os valores possíveis que um usuário pode inserir para uma determinada entrada, você poderá fornecer um conjunto finito de valores que um usuário deve selecionar. Você pode usar DropdownSinglSelect, CheckboxMultiSelect e RadioSingleSelectUserInputType para essa finalidade. Neste artigo, você usará um tipo de entrada RadioSingleSelect:

  1. No VS Code, abra o arquivo ContosoCustomPolicy.XML.

  2. No elemento ClaimsSchema do arquivo ContosoCustomPolicy.XML, declare o seguinte tipo de declaração:

        <ClaimType Id="accountType">
            <DisplayName>Account Type</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>The type of account used by the user</UserHelpText>
            <UserInputType>RadioSingleSelect</UserInputType>
            <Restriction>
                <Enumeration Text="Contoso Employee Account" Value="work" SelectByDefault="true"/>
                <Enumeration Text="Personal Account" Value="personal" SelectByDefault="false"/>
            </Restriction>
        </ClaimType>
    

    Fizemos a declaração accountType. Quando o valor da declaração é coletado do usuário, o usuário deve escolher Conta de Funcionário da Contoso para um valor de trabalho ou Conta Pessoal para um valor pessoal.

    O Azure AD B2C também permite que você acomode sua política para idiomas diferentes e fornece as restrições de tipo de conta para vários idiomas. Para obter mais informações, verifique Localizar a interface do usuário do artigo Adicionar atributos de usuário.

  3. Localize o perfil técnico com Id="UserInformationCollector", adicione a declaração accountType como declaração de exibição usando o seguinte código:

        <DisplayClaim ClaimTypeReferenceId="accountType" Required="true"/>
    
  4. No perfil técnico com Id="UserInformationCollector", adicione a declaração accountType como uma declaração de saída usando o seguinte código:

        <OutputClaim ClaimTypeReferenceId="accountType"/>
    
  5. Para incluir a declaração de tipo de conta no token de acesso, localize o elemento RelyingParty, adicione a declaração accountType como uma declaração de token usando o seguinte código:

        <OutputClaim ClaimTypeReferenceId="accountType" />
    

Etapa 2 – Validar a entrada de usuário usando expressões regulares

Quando não é possível saber todos os valores de entrada de usuário possíveis com antecedência, você permite que o usuário insira os dados por conta própria. Nesse caso, você pode usar expressões regulares (regex) ou padrão para ditar como uma entrada de usuário precisa ser formatada. Por exemplo, um email deve ter o símbolo arroba (@) e um ponto (.) em algum lugar em seu texto.

Quando você faz uma declaração, a política personalizada permite que você defina um regex, que a entrada de usuário deve corresponder. Opcionalmente, você pode fornecer uma mensagem, que é mostrada ao usuário, se sua entrada não corresponder à expressão.

  1. Localize o elemento ClaimsSchema e declare a declaração de email usando o seguinte código:

        <ClaimType Id="email">
            <DisplayName>Email Address</DisplayName>
            <DataType>string</DataType>
            <DefaultPartnerClaimTypes>
                <Protocol Name="OpenIdConnect" PartnerClaimType="email"/>
            </DefaultPartnerClaimTypes>
            <UserHelpText>Your email address. </UserHelpText>
            <UserInputType>TextBox</UserInputType>
            <Restriction>
                <Pattern RegularExpression="^[a-zA-Z0-9.!#$%&amp;&apos;^_`{}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$" HelpText="Please enter a valid email address something like maurice@contoso.com"/>
            </Restriction>
        </ClaimType>
    
  2. Localize o perfil técnico com Id="UserInformationCollector", adicione a declaração de email como declaração de exibição usando o seguinte código:

        <DisplayClaim ClaimTypeReferenceId="email" Required="true"/>
    
  3. No perfil técnico com Id="UserInformationCollector", adicione a declaração de email como uma declaração de saída usando o seguinte código:

        <OutputClaim ClaimTypeReferenceId="email"/>
    
  4. Localize o elemento RelyingParty, adicione o email como uma declaração de token usando o seguinte código:

        <OutputClaim ClaimTypeReferenceId="email" />
    

Etapa 3 – Validar a entrada de usuário usando predicados

Você usou regex para validar entradas de usuário. No entanto, regex tem uma fraqueza, ou seja, a mensagem de erro é exibida até que você corrija a entrada sem mostrar o requisito específico de que a entrada está ausente.

As validações de predicados permitem que você resolva esse problema permitindo que você defina um conjunto de regras (predicados) e uma mensagem de erro independente para cada regra. Em políticas personalizadas, um predicado tem um método embutido, que define as verificações que você deseja fazer. Por exemplo, você pode usar o método de predicado IsLengthRange para verificar se uma senha de usuário está dentro do intervalo de parâmetros mínimos e máximos (valores) especificados.

Embora os predicados definam a validação para verificar um tipo de declaração, PredicateValidations agrupa um conjunto de predicados para formar uma validação de entrada do usuário que pode ser aplicada a um tipo de declaração. Por exemplo, você cria um grupo de predicados de validação que valida diferentes tipos de caracteres permitidos para uma senha. Os elementos predicados e PredicateValidations são elementos filhos da seção BuildingBlocks do arquivo de política.

  1. Localize o elemento ClaimsSchema e faça a declaração de senha usando o seguinte código:

        <ClaimType Id="password">
          <DisplayName>Password</DisplayName>
          <DataType>string</DataType>
          <AdminHelpText>Enter password</AdminHelpText>
          <UserHelpText>Enter password</UserHelpText>
          <UserInputType>Password</UserInputType>
        </ClaimType>
    
  2. Adicione um elemento Predicates como um filho da seção BuildingBlocks usando o seguinte código. Adicione o elemento Predicates abaixo do elemento ClaimsSchema:

        <Predicates>
    
        </Predicates>
    
  3. Dentro do elemento Predicates, defina predicados usando o seguinte código:

      <Predicate Id="IsLengthBetween8And64" Method="IsLengthRange" HelpText="The password must be between 8 and 64 characters.">
        <Parameters>
          <Parameter Id="Minimum">8</Parameter>
          <Parameter Id="Maximum">64</Parameter>
        </Parameters>
      </Predicate>
    
      <Predicate Id="Lowercase" Method="IncludesCharacters" HelpText="a lowercase letter">
        <Parameters>
          <Parameter Id="CharacterSet">a-z</Parameter>
        </Parameters>
      </Predicate>
    
      <Predicate Id="Uppercase" Method="IncludesCharacters" HelpText="an uppercase letter">
        <Parameters>
          <Parameter Id="CharacterSet">A-Z</Parameter>
        </Parameters>
      </Predicate>
    
      <Predicate Id="Number" Method="IncludesCharacters" HelpText="a digit">
        <Parameters>
          <Parameter Id="CharacterSet">0-9</Parameter>
        </Parameters>
      </Predicate>
    
      <Predicate Id="Symbol" Method="IncludesCharacters" HelpText="a symbol">
        <Parameters>
          <Parameter Id="CharacterSet">@#$%^&amp;*\-_+=[]{}|\\:',.?/`~"();!</Parameter>
        </Parameters>
      </Predicate>
    
      <Predicate Id="PIN" Method="MatchesRegex" HelpText="The password must be numbers only.">
        <Parameters>
          <Parameter Id="RegularExpression">^[0-9]+$</Parameter>
        </Parameters>
      </Predicate>
    
      <Predicate Id="AllowedCharacters" Method="MatchesRegex" HelpText="An invalid character was provided.">
        <Parameters>
          <Parameter Id="RegularExpression">(^([0-9A-Za-z\d@#$%^&amp;*\-_+=[\]{}|\\:',?/`~"();! ]|(\.(?!@)))+$)|(^$)</Parameter>
        </Parameters>
      </Predicate>
    
      <Predicate Id="DisallowedWhitespace" Method="MatchesRegex" HelpText="The password must not begin or end with a whitespace character.">
        <Parameters>
          <Parameter Id="RegularExpression">(^\S.*\S$)|(^\S+$)|(^$)</Parameter>
        </Parameters>
      </Predicate>
    

    Definimos várias regras, que, quando juntas, descreveram uma senha aceitável. Em seguida, você pode agrupar predicados para formar um conjunto de políticas de senha que você pode usar em sua política.

  4. Adicione um elemento PredicateValidations como um filho da seção BuildingBlocks usando o seguinte código. Adicione o elemento PredicateValidations como um filho da seção BuildingBlocks, mas abaixo do elemento Predicates:

        <PredicateValidations>
    
        </PredicateValidations>
    
  5. Dentro do elemento PredicateValidations, defina PredicateValidations usando o seguinte código:

        <PredicateValidation Id="SimplePassword">
            <PredicateGroups>
                <PredicateGroup Id="DisallowedWhitespaceGroup">
                    <PredicateReferences>
                        <PredicateReference Id="DisallowedWhitespace"/>
                    </PredicateReferences>
                </PredicateGroup>
                <PredicateGroup Id="AllowedCharactersGroup">
                    <PredicateReferences>
                        <PredicateReference Id="AllowedCharacters"/>
                    </PredicateReferences>
                </PredicateGroup>
                <PredicateGroup Id="LengthGroup">
                    <PredicateReferences>
                        <PredicateReference Id="IsLengthBetween8And64"/>
                    </PredicateReferences>
                </PredicateGroup>
            </PredicateGroups>
        </PredicateValidation>
        <PredicateValidation Id="StrongPassword">
            <PredicateGroups>
                <PredicateGroup Id="DisallowedWhitespaceGroup">
                    <PredicateReferences>
                        <PredicateReference Id="DisallowedWhitespace"/>
                    </PredicateReferences>
                </PredicateGroup>
                <PredicateGroup Id="AllowedCharactersGroup">
                    <PredicateReferences>
                        <PredicateReference Id="AllowedCharacters"/>
                    </PredicateReferences>
                </PredicateGroup>
                <PredicateGroup Id="LengthGroup">
                    <PredicateReferences>
                        <PredicateReference Id="IsLengthBetween8And64"/>
                    </PredicateReferences>
                </PredicateGroup>
                <PredicateGroup Id="CharacterClasses">
                    <UserHelpText>The password must have at least 3 of the following:</UserHelpText>
                    <PredicateReferences MatchAtLeast="3">
                        <PredicateReference Id="Lowercase"/>
                        <PredicateReference Id="Uppercase"/>
                        <PredicateReference Id="Number"/>
                        <PredicateReference Id="Symbol"/>
                    </PredicateReferences>
                </PredicateGroup>
            </PredicateGroups>
        </PredicateValidation>
        <PredicateValidation Id="CustomPassword">
            <PredicateGroups>
                <PredicateGroup Id="DisallowedWhitespaceGroup">
                    <PredicateReferences>
                        <PredicateReference Id="DisallowedWhitespace"/>
                    </PredicateReferences>
                </PredicateGroup>
                <PredicateGroup Id="AllowedCharactersGroup">
                    <PredicateReferences>
                        <PredicateReference Id="AllowedCharacters"/>
                    </PredicateReferences>
                </PredicateGroup>
            </PredicateGroups>
        </PredicateValidation>
    

    Temos três validações de predicado definidas, StrongPassword, CustomPassword e SimplePassword. Dependendo das características da senha que você deseja que os usuários insiram, você pode usar qualquer uma nas validações de predicado. Neste artigo, usaremos uma senha forte.

  6. Localize o tipo de declaração de senha e adicione a validação de predicado StrongPassword logo após a declaração do elemento UserInputType que ela contém, usando o seguinte código:

        <PredicateValidationReference Id="StrongPassword" />
    
  7. Localize o perfil técnico com Id="UserInformationCollector", adicione a declaração de email como declaração de exibição usando o seguinte código:

        <DisplayClaim ClaimTypeReferenceId="password" Required="true"/>
    
  8. No perfil técnico com Id="UserInformationCollector", adicione a declaração de senha como uma declaração de saída usando o seguinte código:

        <OutputClaim ClaimTypeReferenceId="password"/>
    

Observação

Por motivos de segurança, não adicionaremos a senha de um usuário como uma declaração no token gerado por sua política. Portanto, não adicionamos a declaração de senha ao elemento de terceira parte confiável.

Etapa 4 – Validar senha e confirmar senha

Você pode exigir que os usuários insiram a senha duas vezes como um meio de confirmar que o usuário se lembra da senha inserida. Nesse caso, você deve verificar se os valores das duas entradas correspondem. A política personalizada fornece uma maneira fácil de atingir esse requisito. Os tipos de declaração password e reenterPassword são considerados especiais, portanto, quando eles são usados para coletar entradas de usuário, a interface do usuário valida que o usuário reinseriu corretamente sua senha.

Use as seguintes etapas para validar a nova inserção de senha em sua política personalizada:

  1. Na seção ClaimsSchema do arquivo ContosoCustomPolicy.XML, faça a declaração reenterPassword logo após a declaração de senha usando o seguinte código:

        <ClaimType Id="reenterPassword">
            <DisplayName>Confirm new password</DisplayName>
            <DataType>string</DataType>
            <AdminHelpText>Confirm new password</AdminHelpText>
            <UserHelpText>Reenter password</UserHelpText>
            <UserInputType>Password</UserInputType>
        </ClaimType>    
    
  2. Para coletar a entrada de confirmação de senha do usuário, localize o perfil técnico autodeclarado UserInformationCollector, adicione a declaração reenterPassword como uma declaração de exibição usando o seguinte código:

        <DisplayClaim ClaimTypeReferenceId="reenterPassword" Required="true"/>
    
  3. Em seu arquivo ContosoCustomPolicy.XML, localize o perfil técnico autodeclarado UserInformationCollector, adicione a declaração reenterPassword como uma declaração de saída usando o seguinte código:

        <OutputClaim ClaimTypeReferenceId="reenterPassword"/>
    

Etapa 5 – Carregar arquivo de política personalizado

Neste ponto, você criou sua política para abordar as três primeiras abordagens de validação de entrada de usuário.

Siga as etapas em Carregar arquivo de política personalizado. Se você estiver carregando um arquivo com o mesmo nome que o que já está no portal, selecione Substituir a política personalizada se ela já existir.

Etapa 6 – Testar a política personalizada

  1. Em Políticas personalizadas, selecione B2C_1A_CONTOSOCUSTOMPOLICY.

  2. Em Selecionar aplicativo na página de visão geral da política personalizada, selecione o aplicativo Web chamado webapp1 que você registrou anteriormente. Verifique se o valor Selecionar URL de resposta está definido como https://jwt.ms.

  3. Selecione o botão Executar agora.

  4. Insira Nome e Sobrenome.

  5. Selecione Tipo de Conta.

  6. Em Endereço de Email, insira um valor de email que não esteja bem formatado, como maurice@contoso.

  7. Em Senha, insira o valor de senha que não obedeça a todas as características de uma senha forte como definido.

  8. Selecione o botão Continuar. Você verá uma tela semelhante à mostrada abaixo:

    screenshot of validating user inputs.

    Corrija suas entradas antes de continuar.

  9. Insira os valores corretos conforme sugerido pelas mensagens de erro e selecione o botão Continuar novamente. Depois que a política concluir a execução, você será redirecionado para https://jwt.ms e verá um token JWT decodificado. O token é semelhante ao seguinte snippet de token JWT:

    {
      "typ": "JWT",
      "alg": "RS256",
      "kid": "pxLOMWFg...."
    }.{
      ...
      "sub": "c7ae4515-f7a7....",
      ...
      "acr": "b2c_1a_contosocustompolicy",
      "accountType": "work",
      ...
      "email": "maurice@contoso.com",
      "name": "Maurice Paulet",
      "message": "Hello Maurice Paulet"
    }.[Signature]

Etapa 7 – Validar a entrada de usuário usando perfis técnicos de validação

As técnicas de validação que usamos nas etapas 1, 2 e 3 não são aplicáveis a todos os cenários. Se suas regras de negócios forem complexas para serem definidas no nível da declaração, você poderá configurar um técnico de validação e chamá-lo a partir de um perfil técnico autodeclarado.

Observação

Somente perfis técnicos autodeclarados podem usar perfis técnicos de validação. Saiba mais sobre o perfil técnico de validação

Visão geral do cenário

Exigimos que, se o tipo de conta do usuário for conta de funcionário da Contoso, devemos garantir que seu domínio de email seja baseado em um conjunto de domínios predefinidos. Esses domínios são contoso.com, fabrikam.com e woodgrove.com. Caso contrário, mostraremos um erro ao usuário até que ele use uma conta de funcionário da Contoso válida ou alterne para uma conta pessoal.

Saiba como validar a entrada de usuário usando perfis técnicos de validação. Você usa um perfil técnico de validação de tipo de transformação de declarações, mas também pode chamar um serviço de API REST para validar dados, pois aprenderá mais adiante nesta série.

  1. Na seção ClaimsSchema do arquivo ContosoCustomPolicy.XML, faça as declarações domain e domainStatus usando o seguinte código:

        <ClaimType Id="domain">
          <DataType>string</DataType>
        </ClaimType>
    
        <ClaimType Id="domainStatus">
          <DataType>string</DataType>
        </ClaimType>
    
  2. Localize a seção ClaimsTransformations e configure transformações de declarações usando o seguinte código:

        <ClaimsTransformation Id="GetDomainFromEmail" TransformationMethod="ParseDomain">
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="emailAddress"/>
            </InputClaims>
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="domain" TransformationClaimType="domain"/>
            </OutputClaims>
        </ClaimsTransformation>
        <ClaimsTransformation Id="LookupDomain" TransformationMethod="LookupValue">
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="domain" TransformationClaimType="inputParameterId"/>
            </InputClaims>
            <InputParameters>
                <InputParameter Id="contoso.com" DataType="string" Value="valid"/>
                <InputParameter Id="fabrikam.com" DataType="string" Value="valid"/>
                <InputParameter Id="woodgrove.com" DataType="string" Value="valid"/>
                <InputParameter Id="errorOnFailedLookup" DataType="boolean" Value="true"/>
            </InputParameters>
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="domainStatus" TransformationClaimType="outputClaim"/>
            </OutputClaims>
        </ClaimsTransformation>
    

    A transformação de declarações GetDomainFromEmail extrai um domínio do email usando o método ParseDomain e o armazena na declaração de domínio. A transformação de declarações LookupDomain usa o domínio extraído para verificar se ele é válido pesquisando-o nos domínios predefinidos e atribuindo válido à declaração domainStatus.

  3. Use o código a seguir para adicionar um perfil técnico no mesmo provedor de declarações que o perfil técnico com Id=UserInformationCollector:

        <TechnicalProfile Id="CheckCompanyDomain">
            <DisplayName>Check Company validity </DisplayName>
            <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
            <InputClaimsTransformations>
                <InputClaimsTransformation ReferenceId="GetDomainFromEmail"/>
            </InputClaimsTransformations>
            <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="domain"/>
            </OutputClaims>
            <OutputClaimsTransformations>
                <OutputClaimsTransformation ReferenceId="LookupDomain"/>
            </OutputClaimsTransformations>
        </TechnicalProfile>
    

    Declaramos o perfil técnico de transformação de declarações, que executa as transformações de declarações GetDomainFromEmail e LookupDomain.

  4. Localize o perfil técnico com Id=UserInformationCollector e um ValidationTechnicalProfile logo após o elemento OutputClaims usando o seguinte código:

        <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="CheckCompanyDomain">
                <Preconditions>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
                        <Value>accountType</Value>
                        <Value>work</Value>
                        <Action>SkipThisValidationTechnicalProfile</Action>
                    </Precondition>
                </Preconditions>
            </ValidationTechnicalProfile>
        </ValidationTechnicalProfiles>
    

    Adicionamos um perfil técnico de validação ao perfil técnico autodeclarado UserInformationCollector. O perfil técnico será ignorado somente se o valor accountType não for igual ao trabalho. Se o perfil técnico for executado e o domínio de email não for válido, será gerado um erro.

  5. Localize o perfil técnico com Id=UserInformationCollector e adicione o código a seguir dentro da marca metadata.

        <Item Key="LookupNotFound">The provided email address isn't a valid Contoso Employee email.</Item>
    

    Configuramos um erro personalizado caso o usuário não use um email válido.

  6. Siga as instruções em Carregar arquivo de política personalizado para carregar o arquivo de política.

  7. Siga as instruções na etapa 6 para testar sua política personalizada:

    1. Em Tipo de Conta, selecione Conta de Funcionário da Contoso
    2. Em Endereço de Email, insira um endereço de email inválido, como maurice@fourthcoffee.com.
    3. Insira o restante dos detalhes conforme necessário e selecione Continuar

    Como maurice@fourthcoffee.com não é um email válido, você verá um erro semelhante ao mostrado na captura de tela abaixo. Você deve usar um endereço de email válido para executar com êxito a política personalizada e receber um token JWT.

    screenshot of error due to invalid email address.

Próximas etapas