0

I am stuck into a scenario which goes something like this.

I am implementing Identity 2.0 with my new MVC application. I want to go with the database first approach with User Id as int.

To accomplish this, I created

  • Custom User Store - MyUserStore

     public class MyUserStore : IUserLoginStore<AspNetUser>, IUserClaimStore<AspNetUser>, IUserRoleStore<AspNetUser>, IUserPasswordStore<AspNetUser>, IUserSecurityStampStore<AspNetUser>, IUserStore<AspNetUser>, IDisposable //where AspNetUser : AspNetUser
        {
            private readonly DemoPermissionDBContext _context;
            //private readonly Func<string, string> _partitionKeyFromId;
    
            public MyUserStore(DemoPermissionDBContext dbContext)
            {
                _context = dbContext;
            }
    
            public Task SetPasswordHashAsync(AspNetUser user, string passwordHash)
            {
                user.PasswordHash = passwordHash;
                return Task.FromResult(0);
            }
    
            //And other methods implementation
         }
    

Here AspNetUser is the user class which is generated by EF and i made it inherited from Identity.IUser

  • Custom User Manager - AppUserManager

         public class AppUserManager : Microsoft.AspNet.Identity.UserManager<AspNetUser>
         {
              MyUserStore _store = null;
    
              public AppUserManager(MyUserStore store) : base(store)
              {
                   _store = store;
              }
    
         }
    
  • Custom Password Hasher - MyPasswordHasher

    public class MyPasswordHasher : IPasswordHasher
    {
        public string HashPassword(string password)
        {
            return password;
        }
    
        public PasswordVerificationResult VerifyHashedPassword(
          string hashedPassword, string providedPassword)
        {
            if (hashedPassword == HashPassword(providedPassword))
                return PasswordVerificationResult.Success;
            else
                return PasswordVerificationResult.Failed;
        }
     }
    
  • Custom Claim Prinicipal - AppClaimsPrincipal

     public class AppClaimsPrincipal : ClaimsPrincipal
     {
          public AppClaimsPrincipal(ClaimsPrincipal principal):base(principal)
          { 
    
          }
    
          public int UserId
          {
              get { return int.Parse(this.FindFirst(ClaimTypes.Sid).Value);
          }
     }
    

    Now, when i register user, UserManager.CreateAsync should automatically call the SetPasswordHashAsync before actually saving the user to DB. At the same time, SetSecurityStampAsync is being called properly.

What i do in my AccountController is something like this,

public AppUserManager UserManager { get; private set; }

public AccountController(AppUserManager userManager)
{
    this.UserManager = userManager;
    this.UserManager.PasswordHasher = new MyPasswordHasher();

}

This is how i have implemented identity to user int primary key for users table and database first approach.

Question:

When my user is inserted in database, it has no password hash included. The record has null password hash. When i debugged the code, i found that SetPasswordHashAsync is not called only. It does not execute the menthod. What should be causing this issue? I have checked the entire code line by line but no success. Is there anything that i need to add that in web.config for using custom password hasher?

I am not sure if i am missing something. Any help is greatly appreciated.

jparthj
  • 1,606
  • 3
  • 20
  • 44
  • I was having a similar issue and found this question.. not sure if it's same as your problem, but eventually (and obviously in the end..) I found that I was calling `UserManager.CreateAsync(user)` when I should have been calling `UserManager.CreateAsync(user, password)`, otherwise the password doesn't get used and the hashing functions don't get called. – steve16351 Oct 07 '15 at 21:14

2 Answers2

1

I don't see you setting MyPasswordHasher in userManager. Add

this.PasswordHasher = new MyPasswordHasher();

in constructor of AppUserManager.

Also you don't need to override ClaimsPrincipal to get UserId out. This is available through User.Identity.GetUserId(), available in Microsoft.AspNet.Identity namespace.

Also I find it easier to have extension methods on IPrincipal to get values of claims out - easier than messing about with custom principal type.

trailmax
  • 34,305
  • 22
  • 140
  • 234
0

As steve16351 mentioned UserManager.CreateAsync(user, password) should be called instead of UserManager.CreateAsync(user).

I've recently faced the exact same problem as you and solved it with UserManager.CreateAsync(user, password).

feafarot
  • 11
  • 4