One of the key features added to ASP.NET core with the release of Visual Studio 2013 is the new Identity System. If you create a new ASP.NET project, may it be a Web Forms or an MVC project, you will find the default authentication type selected as "Individual User Accounts".
The individual user authentication type creates authentication system based on the Identity system, which looks greatly simplified when compared with the Membership system we had in earlier version. The default project template includes the following references (also available via NuGet packages with same names):
The default templates make use of Entity Framework to persist the user’s information in a SQL Server database. The default database used is an MDF file.
Classes and Setup:
The project template includes Owin and Katana. In the authorization configuration, we see the following setings applied to setup cookie based authentication system on Owin:
It makes the authentication system sharable across Web forms, MVC, Web API and SignalR without adding any additional code. The authentication configuration is called from Owin start-up class. In the models folder of the project, a file with following code is added for us:
As we see, this file includes two classes:
Once the application is executed, a SQL server MDF file is created with the following tables:
User management:
To manage the users and their data, the application uses the following two classes:
Let’s see how a new user registration works. In the AccountController of the MVC project, we find the following code in the Register action method (Similar code can be found in Register.aspx.cs of Web Forms project):
The UserManager.CreateAsync() method calls UserStore.CreateAsync to store the user information in Database. Once the registration is succeeded, a call to SignInAsync is made to authenticate the user. Following is the code inside SignInAsync method:
The AuthenticationManager used here is the Authentication object of the current Owin context. The first statement clears any external cookies in the current application context. Then it asks the UserManager to create a claims-based identity for the current user and then the obtained claims-based identity object is set to the current Owin context.
The Login action method differs by just one statement, it is shown below:
The FindAsync method returns null if the user’s credentials are not valid. If credentials are valid, it returns all information about the user. Once the user is found, a claims-based identity object of the user is set to the Owin context.
LogOff is a straight forward implementation. It just calls the SignOut method of the Authentication object of the Owin context:
Similarly, the template also generates code for changing password, removing user account and to handle external login accounts. We will see how the identity system manages external logins in a future post.
Happy coding!
The individual user authentication type creates authentication system based on the Identity system, which looks greatly simplified when compared with the Membership system we had in earlier version. The default project template includes the following references (also available via NuGet packages with same names):
- Microsoft.AspNet.Identity.Core: Consists of the core classes and interfaces for identity system
- Microsoft.AspNet.Identity.EntityFramework: Consists of classes implemented for Identity system using ADO.NET Entity Framework
The default templates make use of Entity Framework to persist the user’s information in a SQL Server database. The default database used is an MDF file.
Classes and Setup:
The project template includes Owin and Katana. In the authorization configuration, we see the following setings applied to setup cookie based authentication system on Owin:
app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login") }); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
It makes the authentication system sharable across Web forms, MVC, Web API and SignalR without adding any additional code. The authentication configuration is called from Owin start-up class. In the models folder of the project, a file with following code is added for us:
public class ApplicationUser : IdentityUser { } public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnection") { } }
As we see, this file includes two classes:
- ApplicationUser: Inherited from Microsoft.AspNet.Identity.EntityFramework.IdentityUser. The IdentityUser class is inherited from the interface IUser. Any user class in the identity system must inherit from this interface. The class IdentityUser includes all necessary properties needed for a user account, like UserName, PasswordHash, SecurityStamp. This class allows us to add our own properties to a user’s profile. For example, if your web site needs to capture e-mail ID and phone number of the user, you can add them to this page. The IdentityUser class also includes navigation properties for UserRoles, UserClaims and UserLogins. The UserLogin entity is used to store information when a user is logged in using an external authentication provider, like Google, Microsoft, Twitter or Facebook.
- ApplicationDbContext: It is the Entity Framework code-first DbContext class to create the database with necessary tables. It is extended from IdentityDbContext, the DbContext class defined in Microsoft.AspNet.Identity.EntityFramework namespace. It includes DbSets for User and Role. This class allows us to add our own DbSets to the database being created.
Once the application is executed, a SQL server MDF file is created with the following tables:
User management:
To manage the users and their data, the application uses the following two classes:
- UserStore: A class in Microsoft.AspNet.Identity.EntityFramework namespace. It is responsible for all database operations related to managing users. It needs a DbContext for its work; we generally pass in an instance of the IdentityDbContext. This class implements six interfaces: IUserStore, IUserPasswordStore, IUserLoginStore, IUserClaimStore, IUserRoleStore and IUserSecurityStampStore. Each of them has a specific purpose. IUserStore is for creating, finding, updating and deleting the user information; IUserPasswordStore is for managing password and so on. While writing a custom Identity system, IUserStore is the least interface to be implemented. All methods declared in all of these interfaces are asynchronous and they return Task.
- UserManager: This class is defined in the Microsoft.AspNet.Identity.Core assembly. It needs an instance of IUserStore type. The UserManager can be viewed as a repository that calls specific methods of UserStore to manage users for the application. As in UserStore, methods of UserManager are also asynchronous.
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
Let’s see how a new user registration works. In the AccountController of the MVC project, we find the following code in the Register action method (Similar code can be found in Register.aspx.cs of Web Forms project):
var user = new ApplicationUser() { UserName = model.UserName }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home"); }
The UserManager.CreateAsync() method calls UserStore.CreateAsync to store the user information in Database. Once the registration is succeeded, a call to SignInAsync is made to authenticate the user. Following is the code inside SignInAsync method:
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
The AuthenticationManager used here is the Authentication object of the current Owin context. The first statement clears any external cookies in the current application context. Then it asks the UserManager to create a claims-based identity for the current user and then the obtained claims-based identity object is set to the current Owin context.
The Login action method differs by just one statement, it is shown below:
var user = await UserManager.FindAsync(model.UserName, model.Password);
The FindAsync method returns null if the user’s credentials are not valid. If credentials are valid, it returns all information about the user. Once the user is found, a claims-based identity object of the user is set to the Owin context.
LogOff is a straight forward implementation. It just calls the SignOut method of the Authentication object of the Owin context:
Context.GetOwinContext().Authentication.SignOut();
Similarly, the template also generates code for changing password, removing user account and to handle external login accounts. We will see how the identity system manages external logins in a future post.
Happy coding!