ASP .NET Core 3.1 - Usando o Identity de cabo a rabo - V


Hoje vamos continuar a série de artigos mostrando como usar o ASP .NET Core Identiy na versão 3.1 da ASP .NET .Core e do EF Core.

Continuando a quarta parte do artigo veremos como tratar a complexidade das senhas usadas no Identity.

Por padrão, o Identity não permite a criação de senhas simples para proteger nosso aplicativo contra ataques automatizados de força bruta.

Quando tentamos registrar uma nova conta de usuário com uma senha simples como abc ou 123, a criação da conta falha e você verá os seguintes erros de validação :

No Identity as configurações padrão da senha são especificadas na classe PasswordOptions.

Você pode encontrar o código-fonte dessa classe no repositório asp.net do github asp.net no seguinte link: https://github.com/aspnet/AspNetCore

Basta procurar no repositório a classe PasswordOptions.

O seu código fonte é mostrado a seguir:

public class PasswordOptions
{
    public int RequiredLength { get; set; } = 6;
    public int RequiredUniqueChars { get; set; } = 1;
    public bool RequireNonAlphanumeric { get; set; } = true;
    public bool RequireLowercase { get; set; } = true;
    public bool RequireUppercase { get; set; } = true;
    public bool RequireDigit { get; set; } = true;
}

Podemos assim sobrescrever as configurações padrão das senhas na Asp.Net Core Identity.

Podemos fazer isso usando o método Configure da interface IServiceCollection no método ConfigureServices da classe Startup :

     public void ConfigureServices(IServiceCollection services)
     {
          ...
          services.Configure<IdentityOptions>(options =>
          {
                options.Password.RequiredLength = 10;
                options.Password.RequiredUniqueChars = 3;
                options.Password.RequireNonAlphanumeric = false;
           });
           services.AddControllersWithViews();
      }

Podemos também incluindo serviços no Identity :

 public void ConfigureServices(IServiceCollection services)
 {
          ...
            services.AddIdentity<IdentityUser, IdentityRole>(options =>
            {
                options.Password.RequiredLength = 10;
                options.Password.RequiredUniqueChars = 3;
                options.Password.RequireNonAlphanumeric = false;
            })
            .AddEntityFrameworkStores<AppDbContext>();
   ...
 }

Neste exemplo, estamos usando o objeto IdentityOptions para configurar o PasswordOptions.

Esta é uma forma de reconfigurar a formatação original dos requisitos mínimos para a senha do Identity. Não seria aconselhável usar uma forma menos segura mas em cenários de desenvolvimento podemos aplicar um padrão menos rigoroso para realizar testes.

Agora você pode ir além e criar o seu próprio validador de senha customizado para ASP .NET Core Identity. Para fazer isso você pode implementar a interface IPasswordValidator<TUser>.

public interface IPasswordValidator<TUser> where TUser : class
{
    Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password);
}

Uma coisa a observar sobre essa interface é que o parâmetro do tipo TUser é limitado apenas à classe - isso significa que, se você criar a implementação mais genérica dessa interface, não poderá usar propriedades do parâmetro do usuário.

A seguir um exemplo bem básico de uma implementação:

 public class PoliticaSenhaPersonalizada : PasswordValidator<AppUser>
 {
      public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager,
     AppUser user, string password)
        {
            IdentityResult result = await base.ValidateAsync(manager, user, password);
            List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList(); 

            if (password.ToLower().Contains(user.UserName.ToLower()))
            {
                errors.Add(new IdentityError
                {
                    Description = "A senha não pode conter o nome do usuário"
                });
            }
            if (password.Contains("123"))
            {
                errors.Add(new IdentityError
                {
                    Description = "A senha não deve conter a sequência 123"
                });
            }
            return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
        }
    }

Após esta implementação basta registrar o serviço na classe Startup.

Não vou entrar nos detalhes desta implementação mas fica aqui o registro dessa possibilidade.

No próximo artigo veremos veremos como exibir e/ou ocultar os links para login e registro do usuário na barra de navegação e como implementar o Logout do usuário.

"Bendito seja o Deus e Pai de nosso Senhor Jesus Cristo, o Pai das misericórdias e o Deus de toda a consolação;
Que nos consola em toda a nossa tribulação, para que também possamos consolar os que estiverem em alguma tribulação, com a consolação com que nós mesmos somos consolados por Deus."
2 Coríntios 1:3,4

Referências:


José Carlos Macoratti