재우니의 블로그

IdentitityFramework 2 Custom SHA256 IPasswordHasher with Salt


https://gist.github.com/theuntitled/3561ac32a5e2d79fe505963a87382dc0



IdentitityFramework 2 Custom SHA256 IPasswordHasher with Salt

CustomPasswordHasher.cs


using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNet.Identity;

namespace Project
{

    public class CustomPasswordHasher<TUser> : ICustomPasswordHasher<TUser> where TUser : class , IUser<string>
    {

        public string HashPassword( string password )
        {
            throw new NotSupportedException();
        }

        public PasswordVerificationResult VerifyHashedPassword( string hashedPassword , string providedPassword )
        {
            throw new NotSupportedException();
        }

        public string HashPassword( string password , TUser user )
        {
            var sha256 = new SHA256Managed();

            var hashBytes = sha256.ComputeHash( Encoding.UTF8.GetBytes( string.Concat( password , user.UserName ) ) );

            var hash = new StringBuilder();

            foreach ( var hashByte in hashBytes )
            {
                hash.Append( hashByte.ToString( "x2" ) );
            }

            return hash.ToString();
        }

        public PasswordVerificationResult VerifyHashedPassword( string hashedPassword , string providedPassword , TUser user )
        {
            return HashPassword( providedPassword , user ) == hashedPassword
                ? PasswordVerificationResult.Success
                : PasswordVerificationResult.Failed;
        }

    }

}



ICustomPasswordHasher.cs


using Microsoft.AspNet.Identity;

namespace Project
{

    public interface ICustomPasswordHasher<in TUser> : IPasswordHasher where TUser : class , IUser<string>
    {

        string HashPassword( string password , TUser user );

        PasswordVerificationResult VerifyHashedPassword( string hashedPassword , string providedPassword , TUser user );

    }

}


UserManager.cs


using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security.DataProtection;

namespace Project
{

    public class UserManager : UserManager<ApplicationUser> , IUserManager
    {

        public UserManager( IUserStore<ApplicationUser> store ) : base( store )
        {
            UserValidator = new UserValidator<ApplicationUser>( this ) {
                RequireUniqueEmail = true ,
                AllowOnlyAlphanumericUserNames = true
            };

            PasswordValidator = new PasswordValidator {
                RequiredLength = 8 ,
                RequireDigit = true ,
                RequireLowercase = true ,
                RequireUppercase = true ,
                RequireNonLetterOrDigit = true
            };

            PasswordHasher = new CustomPasswordHasher<ApplicationUser>();

            UserLockoutEnabledByDefault = false;

            if ( DefaultDataProtectionProvider != null )
            {
                UserTokenProvider =
                    new DataProtectorTokenProvider<ApplicationUser>( DefaultDataProtectionProvider.Create( "ASP.NET Identity" ) );
            }
        }

        public static IDataProtectionProvider DefaultDataProtectionProvider { get; set; }

        private CustomPasswordHasher<ApplicationUser> GetPasswordHasher()
        {
            return PasswordHasher as CustomPasswordHasher<ApplicationUser>;
        }

        private IUserSecurityStampStore<ApplicationUser, string> GetSecurityStore()
        {
            var securityStampStore = Store as IUserSecurityStampStore<ApplicationUser, string>;

            if ( securityStampStore == null )
            {
                throw new NotSupportedException("Store does not implement IUserSecurityStampStore<ApplicationUser>");
            }

            return securityStampStore;
        }

        protected override async Task<bool> VerifyPasswordAsync( IUserPasswordStore<ApplicationUser , string> store ,
                                                                 ApplicationUser user ,
                                                                 string password )
        {
            var hash = await store.GetPasswordHashAsync( user );

            return GetPasswordHasher().VerifyHashedPassword( hash , password , user ) != PasswordVerificationResult.Failed;
        }

        protected override async Task<IdentityResult> UpdatePassword( IUserPasswordStore<ApplicationUser , string> passwordStore , ApplicationUser user , string newPassword )
        {
            var validationResult = await PasswordValidator.ValidateAsync( newPassword );

            if ( !validationResult.Succeeded )
            {
                return validationResult;
            }

            await passwordStore.SetPasswordHashAsync( user , GetPasswordHasher().HashPassword( newPassword , user ) );

            await GetSecurityStore().SetSecurityStampAsync( user , Guid.NewGuid().ToString() );

            return IdentityResult.Success;
        }

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
            ApplicationUser user ,
            string authenticationType = DefaultAuthenticationTypes.ApplicationCookie )
        {
            var identity = await CreateIdentityAsync( user , authenticationType );

            identity.AddClaim( new Claim( ClaimTypes.Email , user.Email ) );

            return identity;
        }

    }

}