Forms authentication using ASP.NET Identity & VS 2013 Preview
One of the many new features of Visual Studio 2013 is the new membership system called ASP.NET Identity. The old SimpleMembershipProvider has been replaced. In line with the unification of ASP.NET, ASP.NET Identity can be used for all types of ASP.NET applications (MVC, Web Forms, Web API etc). In this post I will describe how to use ASP.NET Identity to implement forms authentication and show how to customize it to support your requirements.
UPDATE: This post is about the preview version of ASP.NET Identity. For a updated post on the release version see this post: ASP.NET Identity 1.0 Release version
If you create a new MVC project in VS 2013 preview and select authentication using “individual user accounts” you will get a project that references the new ASP.NET Identity assemblies, instead of the WebMatrix assemblies that we got in VS 2012.
You may also notice that the DotNetOpenAuth packages that we used to see in a VS 2012 project are gone. They have been replaced by the Owin assemblies from the Katana Project (http://katanaproject.codeplex.com). ASP.NET Identity is based on OWIN (http://owin.org/) authentication middleware.
The Model
By default ASP.NET Identity is based on entity framework code first, but the model is loosely coupled and well-designed based on interfaces allowing for customization as needed. If your requirements are different from what the stock implementation provides you can easily extend and/or replace parts as needed.
As shown in the diagram above the model consist of a user and the following related objects:
- UserSecret
For forms authentication this will be the hashed password - UserLogin
The loginProvider, for forms authentication this will be “Local”. UserLogin also has the key used to identify the user with the login provider. - UserClaim
A list of claims for the user - Role
A list of the roles that the user has
Identity storage and authentication
Using ASP.NET Identity is very simple. The core functionality is implemented by the two classes IdentityAuthenticationManager and IdentityStoreManager.
The IdentityStoreManagers responsibilities are providing an interface to a generic identity store and password management. The default identity store is an entity framework code first database context working with the database identified by the default connection string, but we can provide our own implementation that could access anything we would like as long as we implement the IIdentityStoreContext interface.
The second class is the IdentityAuthenticationManager which basically provides methods for signing in and signing out. As we will see it also has an important method called GetUserIdentityClaims that builds a list of claims for the signed in user. The IdentityStoreManager should be injected into the IdentityAuthenticationManager using constructor injection as the authentication manager relies on the store manager to access the identity store.
All this is more than you need to know to use out-of-the-box implementation, as the template will create an AccountController that instantiates the two managers and provide methods for Login, Logout, Register user and Change password which will provide forms authentication with a database that has tables for each of the classes described in the previous section (The Model).
Using a custom model
Often we want a richer model than the initial user model described in “The Model”. We may want to store more information about our users than just their user name, and we may even want to model relationships between the users and other concepts.
In a project I am currently involved in we have modeled information about real people in a concept we have called Profile. Some profiles are also users, i.e. they can sign in. All users should have a profile as we want to store information about their name, email etc.
Fortunately ASP.NET Identity model can easily be extended to support this. To see how we need to dig just a little bit deeper into IdentityStoreManager.
The IdentityStoreManager aggregates an object implementing IIdentityStoreContext. If we use the default constructor to create the IdentityStoreManager it will instantiate a default IdentityStoreContext which in turn will create an entity framework DbContext that has 6 DbSets, one for each of the concepts described in the section “The Model” + a UserRole to implement the many-to-many relation between User and Role.
The instantiated DbContext is a generic class with the following template: IdentityDbContext<TUser, TUserClaim, TUserSecret, TUserLogin, TRole, TUserRole>.
The default implementation will use classes from the Microsoft.AspNet.Identity.EntityFramework, but we can “adjust” the default implementation and modify it to our needs.
As we can see from the diagram above the IdentityStoreContext has 5 stores, one for each of the model concepts. The ASP.NET Identity framework provide default implementations of each of these in the form of the 5 generic classes:
UserLoginStore<TUserLogin>
RoleStore<TRole>
UserSecretStore<TUserSecret>
UserClaimStore<TClaimStore>
UserStore<TUser>
To implement our custom user that has a relation to a profile we need to make our own database context inherit from IdentityDbContext<CustomUser, UserClaim, UserSecret, UserLogin, Role, UserRole>
Example
public class CustomUser : Microsoft.AspNet.Identity.EntityFramework.User
{
public int ProfileId { get; set; } // ProfileID
public virtual Profile Profile { get; set; }
}
public class MyDbContext : IdentityDbContext
{
public IDbSet Profiles { get; set; }
}
We also need to implement our own IdentityStoreContext
which has a UserStore
containing CustomUsers instead of the ASP.NET Identity Users.
public class MyIdentityStoreContext : IdentityStoreContext
{
public MyIdentityStoreContext(DbContext context)
: base(context)
{
Users = new UserStore(DbContext);
}
}
Finally we wire it all together in the AccountController (or preferrably in the IOC configuration, but for simplicity we do it directly in the controller here).
public AccountController()
{
IdentityStore = new IdentityStoreManager(
new MyIdentityStoreContext(
new MyDbContext()
)
);
AuthenticationManager = new IdentityAuthenticationManager(IdentityStore);
}
I want clean models!
So far we have seen how simple and well-designed ASP.NET Identity is. It is simple to extend and customize, still there’s one thing that isn’t that great.
Our CustomUser have to inherit from Microsoft.AspNet.Identity.EntityFramework.User. I don’t like to be forced to have my model classes inherit from some third party class. It’s one of the great features about EF code-first that I can have plain POCO classes. I don’t want that ruined by ASP.NET Identity. I am OK with having to implement IUser, but not being forced to inherit from User.
Currently we can’t use the default implementations of the generic DbContext class and the IdentityAuthenticationManager as is if we aren’t inheriting User. I am sure this is just bugs, everything looks like it is designed to be customized. The code uses interfaces and generics everywhere so it would be really weird if these aren’t just oversights that will be fixed before we get the final version.
For those who can’t wait there is still hope though. This far I have only experienced troubles with the GetUserIdentityClaims(string userId, IEnumerable claims) method of IdentityAuthenticationManager and the ValidateEntity method of IdentityDbContext.
They both have a line where they cast to User when they could have cast to IUser and TUser respectively. Fortunately they are both virtual methods and can simply be overridden in custom derived classes, but as mentioned I am sure this will be fixed before release.