Sunday, 2 March 2014

Configuring ASP.NET Identity

[Note: It looks like email is now a first class entity in the database tables as of version 2.0.0.0 of the EF Identity provider]
Recently I’ve been tinkering around with ASP.NET Identity and, like many, have stumbled around in the dark due to lack of documentation – or lack of me being able to find the documentation. Rather than add to the problem I’ll add to the solution, by adding some much-needed documentation as I go.
I have a new project that I want to add ASP.NET Identity to, and after having let the default code whirr around for a while I need to extend it a little. What I want to do is as follows…
  • Add some extra columns to the ‘user’ table
  • Allow email addresses as usernames
I’m sure I may find more things I need to do as I go, but this will do for the moment. I like clear separation of concerns, so am splitting out the data context and associated classes into another assembly for now – that way I can get to grips with it better and also swap it out for something else if necessary. The shell of the solution contains the following classes…
    public abstract class ApplicationUser : IdentityUser
    {
        public string Email { get; set; }
    }



That’s my extended “user” class for now, I’ve added an email property as I need to record that in the database. In my scenario I have two types of user in the system – parents and children. A parent has a username and an email (which may both be the email address), whereas a child may not have an email address.
    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext() : base("DefaultConnection")
        {
        }
    }



This DbContext class derives from the provided IdentityDbContext<TUser> class (that resides in the Microsoft.AspNet.Identity.EntityFramework assembly). You’ll notice that the constructor passes the database connection string “DefaultConnection” to the base class – this is the name used by ASP.NET Identity so I thought I’d use it too. Now to create a user and test what I’ve done so far. I created a simple Console app, created a database in SQL Express, and then fired up the following code…
    using (var ctx = new ApplicationDbContext())
    {
        var store = new UserStore<ApplicationUser>(ctx);
        var manager = new UserManager<ApplicationUser>(store);

        // Now create a user...
        ApplicationUser user = new ApplicationUser
        {
            UserName = "Test",
            Email = "me@here.com"
        };

        var result = manager.Create(user, "password");
    }



The UserManager class is provided by Microsoft.AspNet.Identity, and is a corollary to the Membership class of old – with a few new bits added for good measure, most notably a load of Task<> methods so you can do all of this stuff asynchronously.

The UserStore class provides an EF based implementation of the IUserStore<TUser> interface. So, if you want to store your users somewhere else, just cruft up an IUserStore<> derived class and you’re away - it’s a very small interface…
    public interface IUserStore<TUser> : IDisposable where TUser : Microsoft.AspNet.Identity.IUser
    {
        Task CreateAsync(TUser user);
        Task DeleteAsync(TUser user);
        Task<TUser> FindByIdAsync(string userId);
        Task<TUser> FindByNameAsync(string userName);
        Task UpdateAsync(TUser user);
    }



Not much to override there should you wish to store and retrieve users from somewhere other than the standard store. However, the user store will probably need to do a lot more than just the above, so there are a bunch of additional interfaces that a user store should consider implementing. These are as follows…
    IUserClaimStore<TUser>
    IUserLoginStore<TUser>
    IUserPasswordStore<TUser>
    IUserRoleStore<TUser>
    IUserSecurityStampStore<TUser>

All of these derive from IUserStore<TUser> and the EF provided UserStore class implements the lot. Then there’s a bunch of properties on UserManager that check if the specified user store implements these interfaces and acts accordingly. As an example, you might not want a ‘security stamp’ on your user record – you could create your own class and implement just the bits you need.

Now, UserManager has a bunch of other properties you can set which alter how it does it’s job too. And there’s a bit of strangeness to UserManager which caught me out for a while. I’ve been programming in .NET since 2000 so I’m not a stranger to the odd exception – but when I tried this code I didn’t get any…
    ApplicationUser user = new ApplicationUser
    {
        UserName = "me@here.com",
        Email = "me@here.com"
    };

    var result = manager.Create(user, "password");



OK, so that’s created a user – right? Not in my database it hasn’t. This caught me out for a while – there was no user in the database, but also no exception, so what’s up?

Well, after some head scratching I decided to look at the result from this call and saw this…
    "User name me@here.com is invalid, can only contain letters or digits."



Aha, so that’s my problem. But no exception – hmmm, this library is going to take some getting used to. I cannot remember the last time I explicitly went looking for a “success” code before. What is returned is an IdentityResult instance which includes a Succeeded property and also a bunch of errors in a string collection. Feels like I’m back in the good old days of COM, I’m sure there’s a reason for this design – but that reason was in a meeting probably 3 years ago and hasn’t dribbled down to us. I don’t have an issue with returning multiple errors, that’s fine, but I prefer the way that the Task<> classes do their errors by returning an AggregateException at the end, rather than needing me to plumb the depths of a return code. Oh well.

Permitting emails as usernames


OK, so now to the reason you’re probably here – how do I permit a username to hold an email?

The UserManager class has a UserValidator property which implements IIdentityValidator<TUser>, and the default one doesn’t permit any non-alpha characters in a username. So, you can replace the default, or just alter a property on it as follows…
    var manager = new UserManager<ApplicationUser>(store);
    var val = manager.UserValidator as UserValidator<ApplicationUser>;

    if (null != val)
        val.AllowOnlyAlphanumericUserNames = false;



That’s it – you can now insert usernames that are email addresses. And you could optionally replace the validator with one of your own as you might want to use a regular expression to validate a username, or ensure that the username is not the same as the password and so on. One other thing that the validator does is ensure that no user exists in the database with the same username, which of course your derived class would need to do too.

Adding extra columns to the AspNetUsers table


Due to the magic that is EF 4 (and now 6), by creating my ApplicationUser class above and then adding the Email property (and running against a new database), EF will create the database structure for me so I get a new table with an Email column. Sweet.

By default you get a schema that contains tables prefixed with AspNet, such as AspNetUsers, AspNetRoles and so on. If you want to alter these you can override OnModelCreating in your DbContext class to do something like the following…
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<IdentityUser>().ToTable("Users", "auth");
    }



As an example, the above will store users in a table called Users within the auth schema. Note – if you go down this route I would suggest you don’t call the base class OnModelCreating, and instead copy the code from the base class and alter as necessary (as there’s a few intricacies in there that could bite you).

Wrap Up


With all that in place, I can now store additional information against a user, and I can also use an email address as the username.

15 comments:

Judy Pearson said...

Thanks for sharing this valuable information as this came to my aid after an extensive efforts. I also want to know about configuring Ubuntu on my system as I am a beginner. Do share something like this too

Oliver Maurice said...

To write the great persuasive essay you need to take a look at a couple of these hints. This could be really helpful in the future

Assignment Help said...

Nice Post! The increasing importance of Writing Assignments has prompted students to take a helping hand from
Assignment Writing Help
Excellent assignment help

davidmocond said...

Generally speaking, I agree with the author of the essay, but everything happens a little differently in life. I found another meaning that you will find in the report on the brillassignment review. Thanks for the post anyway, it was really interesting to read,

Unknown said...

Un bon blog est toujours accompagné d'informations nouvelles et excitantes et en lisant, j'ai l'impression que ce blog a vraiment toutes les qualités qui qualifient un blog d'un seul.


https://www.safecasinosite.net

Qasim Khan said...

Exceptional post however, I was wanting to know if you could write a little more on this topic Project Management Assignment Service? I’d be very thankful if you could elaborate a little bit further. Thanks

joellreyy87 said...

Finishing an exposition or a PhD proposition is the best test in your scholarly profession. A great many understudies experience a scope of dissertation service uk various issues while finishing their expositions. From observing important paper titles to picking reasonable examination techniques and in any event, composing the exposition parts.

Shawn Abi said...

All alone, a puffer coat can peruse as really easygoing and energetic. However, there are ways of lifting it and black widow white hooded jacket for sale causing it to feel more cleaned and, surprisingly, proficient. A smooth dark style coordinates pleasantly with a variety of hindered midi dresses and tall cowhide boots, for example, to wear yours to the workplace.

James Charles said...

Chocolaty Gift Baskets. Chocolate Gift to Pakistan. Gift Baskets. Send Chocolates as a gift baskets in karachi. Same-day chocolate gift bushel conveyance. Premium Snack Fun Gift Basket. The sweet tooth of the kids to the saltish inclination of the grown-ups accessible in all of Pakistan

Angel17 said...

Your articles are really helpful. Worth recommending! painting company near me

Shoplectic said...

If you want to wear Shoplectic jackets to work, a smooth dark style goes well with several constrained midi dresses and tall cowhide boots, for instance.

ZuhayrWafiq said...

From keeping an eye out for relevant paper titles to selecting suitable research methods and, in any case, Corporation Tax the exposition portions. In general, I concur with the essay's author, although life sometimes goes a bit differently.

KentSilvester said...

from keeping an eye out for relevant paper titles to selecting suitable research methods and, in any case, writing the exposition parts. If you want to wear yours to work, a smooth dark style goes well with several constrained midi dresses and tall cowhide boots, for instance. digimarketinginc.com

Nandi IVF said...

The Best ivf centre in rohini is renowned for its exceptional fertility care. With state-of-the-art facilities and a team of highly experienced fertility specialists, the center offers personalized and advanced reproductive solutions. Cutting-edge technologies such as In Vitro Fertilization (IVF), Intracytoplasmic Sperm Injection (ICSI), and Preimplantation Genetic Testing (PGT) are employed to maximize success rates.

The compassionate and dedicated staff ensures comprehensive support throughout the fertility journey, fostering a nurturing and comfortable environment for patients. The center's commitment to excellence, innovative treatments, and successful outcomes solidify its reputation as a leading destination for individuals and couples seeking fertility assistance in Rohini.

Anonymous said...

Thank you for sharing such valuable information in your post. social media promotion agency gwalior