27

In the default AccountController created I see

    public AccountController()
        : this(Startup.UserManagerFactory(), Startup.OAuthOptions.AccessTokenFormat)
    {
    }

In Startup.Auth.cs I see

    UserManagerFactory = () => 
                new UserManager<IdentityUser>(new UserStore<IdentityUser>());   

Seems like the implementation of UserStore comes from Microsoft.AspNet.Identity.EntityFramework.

So, to customize the authentication do I have to implement my own version of UserStore like

 class MYSTUFFUserStore<IdentityUser> : UserStore<IdentityUser>
 {
 } 

and override the methods and then do this in Startup.Auth.cs

UserManagerFactory = () => 
               new UserManager<IdentityUser>(new MYSTUFFUserStore<IdentityUser>());   

I am looking for a correct way to customize the authentication.

1 Answer 1

47

Assuming your table is called AppUser, convert your own AppUser domain object to IUser(using Microsoft.AspNet.Identity) like this

using Microsoft.AspNet.Identity;
public class AppUser : IUser
{
    //Existing database fields
    public long AppUserId { get; set; }
    public string AppUserName { get; set; }
    public string AppPassword { get; set; }

    public AppUser()
    {
        this.Id = Guid.NewGuid().ToString();  
    }

    [Ignore]
    public virtual string Id { get; set; }         
    [Ignore]
    public string UserName
    {
        get
        {
            return AppUserName;
        }
        set
        {
            AppUserName = value;
        }
    }
}

Implement the UserStore object like this

using Microsoft.AspNet.Identity;
public class UserStoreService 
         : IUserStore<AppUser>, IUserPasswordStore<AppUser>
{
    CompanyDbContext context = new CompanyDbContext();

    public Task CreateAsync(AppUser user)
    {            
        throw new NotImplementedException();
    }

    public Task DeleteAsync(AppUser user)
    {
        throw new NotImplementedException();
    }

    public Task<AppUser> FindByIdAsync(string userId)
    {
        throw new NotImplementedException();
    }

    public Task<AppUser> FindByNameAsync(string userName)
    {
        Task<AppUser> task = context.AppUsers.Where(
                              apu => apu.AppUserName == userName)
                              .FirstOrDefaultAsync();

        return task;
    }

    public Task UpdateAsync(AppUser user)
    {
        throw new NotImplementedException();
    }

    public void Dispose()
    {
        context.Dispose();
    }

    public Task<string> GetPasswordHashAsync(AppUser user)
    {
        if (user == null)
        {
            throw new ArgumentNullException("user");
        }

        return Task.FromResult(user.AppPassword);
    }

    public Task<bool> HasPasswordAsync(AppUser user)
    {
        return Task.FromResult(user.AppPassword != null);
    }

    public Task SetPasswordHashAsync(AppUser user, string passwordHash)
    {
        throw new NotImplementedException();
    }

}

If you have your own custom password hashing you will also need to implement IPasswordHasher. Below is an example where there is no hashing of the password(Oh no!)

using Microsoft.AspNet.Identity;
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;
    }
}

In Startup.Auth.cs replace

UserManagerFactory = () => 
     new UserManager<IdentityUser>(new UserStore<IdentityUser>());

with

    UserManagerFactory = () => 
     new UserManager<AppUser>(new UserStoreService()) { PasswordHasher = new MyPasswordHasher() };

In ApplicationOAuthProvider.cs, replace IdentityUser with AppUser

In AccountController.cs, replace IdentityUser with AppUser and delete all the external authentication methods like GetManageInfo and RegisterExternal etc.

Sign up to request clarification or add additional context in comments.

4 Comments

thanks for the answer, but how I can get AppUser from another controller for the current request?
User.Identity.Name will give you the username in an authenticated request.
Sunil, can you explain why does custom class "AppUser" need to inplement built-in interface "IUser"?
@Thomas.Benz here is a snippet from an article I found useful: "Microsoft.AspNet.Identity.UserManager<T> where T: IUser This class allows to create, delete and find users as well as to create identities. An identity is created for a user and can be used to make authorization and authentication decisions." The idea here is to use some/most of the built-in features of ASP.NET Identity and then override/replace what you need with a custom implementation - at least that's what I have done here thanks to Sunil's answer

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.