es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Existe alguna forma de cambiar el tipo de dato de PasswordHash de String a Byte array en Asp.Net Core Identity?

Estoy implementando la librería de identidad de asp.net core en el proyecto de API mínima, y el campo PasswordHash de la tabla de usuarios realiza su hashing y salt por defecto, pero yo quiero realizar mi propio hashing y salt de contraseñas.
Entonces, ¿cómo puedo cambiar el tipo de PasswordHash de “string” a “byte[]”?

Además, el campo PasswordHash no debería implementar ningún mecanismo de hashing por defecto.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para cambiar el tipo de PasswordHash de “string” a “byte[]”, puedes personalizar la clase PasswordHasher de la biblioteca ASP.NET Core Identity. Aquí están los pasos:

    1. Crea un nuevo archivo de clase en tu proyecto y llámalo CustomPasswordHasher.
    2. Hereda de la clase PasswordHasher e implementa la interfaz IPasswordHasher, de esta manera:
    using Microsoft.AspNetCore.Identity;
    using System;
    using System.Security.Cryptography;
    
    public class CustomPasswordHasher<tuser> : PasswordHasher<tuser>, IPasswordHasher<tuser> where TUser : class
    {
        private const int SaltSize = 16;
    
        public override string HashPassword(TUser user, string password)
        {
            throw new NotImplementedException("Utiliza en su lugar la sobrecarga HashPassword basada en byte[].");
        }
    
        public override PasswordVerificationResult VerifyHashedPassword(TUser user, string hashedPassword, string providedPassword)
        {
            throw new NotImplementedException("Utiliza en su lugar la sobrecarga VerifyHashedPassword basada en byte[].");
        }
    
        public string HashPassword(TUser user, byte[] password)
        {
            if (password == null)
            {
                throw new ArgumentNullException(nameof(password));
            }
    
            using var rng = new RNGCryptoServiceProvider();
            byte[] salt = new byte[SaltSize];
            rng.GetBytes(salt);
    
            byte[] hash = HashPasswordWithSalt(password, salt);
            byte[] hashedPassword = new byte[hash.Length + salt.Length];
            Array.Copy(salt, 0, hashedPassword, 0, salt.Length);
            Array.Copy(hash, 0, hashedPassword, salt.Length, hash.Length);
    
            return Convert.ToBase64String(hashedPassword);
        }
    
        public PasswordVerificationResult VerifyHashedPassword(TUser user, string hashedPassword, byte[] providedPassword)
        {
            if (hashedPassword == null)
            {
                throw new ArgumentNullException(nameof(hashedPassword));
            }
    
            if (providedPassword == null)
            {
                throw new ArgumentNullException(nameof(providedPassword));
            }
    
            byte[] hashedPasswordBytes = Convert.FromBase64String(hashedPassword);
    
            if (hashedPasswordBytes.Length != (SaltSize + HashSize))
            {
                return PasswordVerificationResult.Failed;
            }
    
            byte[] salt = new byte[SaltSize];
            Array.Copy(hashedPasswordBytes, 0, salt, 0, SaltSize);
    
            byte[] hash = HashPasswordWithSalt(providedPassword, salt);
            byte[] hashedProvidedPassword = new byte[hash.Length + salt.Length];
            Array.Copy(salt, 0, hashedProvidedPassword, 0, salt.Length);
            Array.Copy(hash, 0, hashedProvidedPassword, salt.Length, hash.Length);
    
            return SlowEquals(hashedPasswordBytes, hashedProvidedPassword) ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
        }
    
        private static byte[] HashPasswordWithSalt(byte[] password, byte[] salt)
        {
            using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, IterationCount);
            return pbkdf2.GetBytes(HashSize);
        }
    
        private static bool SlowEquals(byte[] a, byte[] b)
        {
            uint diff = (uint)a.Length ^ (uint)b.Length;
            for (int i = 0; i < a.Length && i < b.Length; i++)
            {
                diff |= (uint)(a[i] ^ b[i]);
            }
            return diff == 0;
        }
    }
    
    1. En el método Configure de tu proyecto de API minimalista, reemplaza services.AddDefaultIdentity por services.AddIdentity y pasa un objeto IdentityOptions de la siguiente manera:
    app.Map("/api/users", usersApp =>
    {
        // ...
    
        services.AddIdentity<user, identityrole="">(options =>
        {
            options.Password.RequireDigit = false;
            options.Password.RequiredLength = 6;
            options.Password.RequireLowercase = false;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = false;
        })
        .AddEntityFrameworkStores<applicationdbcontext>()
        .AddPasswordHasher<><user>>();
    });
    

    Esto configurará tu aplicación para usar tu generador de contraseñas personalizado en lugar de la implementación predeterminada.

    En resumen, para cambiar el tipo de PasswordHash de “string” a “byte[]” e implementar tu propio mecanismo personalizado de hashing y salado, debes crear una clase que herede de PasswordHasher e implemente IPasswordHasher con los métodos necesarios. Luego configuras tu proyecto de API minimalista para usar este generador de contraseñas personalizado en lugar de la implementación predeterminada.</user,>

Comments are closed.