Identity

Any sort of database-driven website which can be administered through a web interface typically requires some form of check to ensure that only authorised users are able to administer it. Most commonly this is done through a user entering (at least) a user name and password. Two concepts which are involved in this process are Authentication and Authorization.

Authentication

The process of checking that a username and password match is called Authentication (i.e. it checks someone is who they say they are - if they are not they shouldn't know the password). The concepts of users and login are crucial to authentication.

Authorisation

The process of verifying that a user has access to a specific feature (i.e. that they are allowed to do something) is known as Authorisation. In ASP.NET the concepts of Roles and secured folders are used in the Authorisation process.

ASP.NET Identity

Over the years a few systems for authenticating users in an ASP.NET web application have existed. One of the newer systems available is ASP.NET Identity. Identity can be added to an existing project, provided a database is available for it to user for storing user information. This tutorial assumes that you have a pre-existing project, for which pages in certain folders need access restrictions applied. It also assumes you have a database which can be used to store user details.

Overriding the authentication mode

Because ASP.NET identity replaces the traditional forms of authentication in ASP.NET (such as Forms or Windows authentication), we need to register in the web.config file that the mode of authentication we are using is 'none'. Add the following code inside the <system.web> section of the web.config file within the root of the application:

<authentication mode="None" />

Adding Identity to your project

Identity can be installed as a package by using the NuGet package manager built into Visual Studio:

  1. Using the menu click Tools > NuGet Package manager > Manage NuGet packages for solution
  2. Choose the browser option and search for Identity
  3. Install the option entitled Microsoft.Asp.NET.Identity.EntityFramework
  4. Select the project in the list and when prompted click OK/Agree

Connecting to a database

In the web.config file, after the configSections section, add a new section called connectionStrings and add a connection string to the database you wish to use. Later code in this tutorial assumes the name of the connection string is IdentityConnectionString

Allowing users to register

Historically websites allowed users to signup with a username and password. Having a username for a website can be somewhat problematic, as users are likely to try and request the same username that someone else has, and may easily forget a username for a website. Instead, many websites now require users to sign up with your email address as your username, this guarantees it to be unique, helps prevent accidental duplicate registrations, and also makes it harder to forget.

  1. Add a new web form to the project, naming it something like Register.aspx
  2. Using the toolbox, add text fields (with associated labels) for a username and password field.

    For the purposes of the tutorial this is all that's required, but a more sensible option is to add fields to confirm the password, so the user doesn't inadvertently signup with the wrong password. It would also be sensible to add validation so the email address entered is a valid email address, and the password meets any minimum complexity rules required.

  3. Add a button with the text 'Register', provide an appropriate ID value for it
  4. Add a literal
  5. Double click the button in the Design View to create an event handler
  6. In the Register.aspx.cs file, add the following statements at the top of the file
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.EntityFramework;
  7. Add the code below to the button event (which assumes the textfields are called txtRegEmail and txtRegPassword and the literal litRegisterError), which will create a user with the supplied credentials:
    //create a dbcontext that specified the connection string
    var identityDbContext = new IdentityDbContext("IdentityConnectionString");
    //create user store and user manager
    var userStore = new UserStore<IdentityUser>(identityDbContext);
    var manager = new UserManager<IdentityUser>(userStore);
    //create user
    var user = new IdentityUser() { UserName = txtRegEmail.Text, Email = txtRegEmail.Text };
    IdentityResult result = manager.Create(user, txtRegPassword.Text);
    if (result.Succeeded)
    {
        //todo: Either authenticate the user (log them in) or redirect them to the login page to log in for themselves
    }
    else
    {
        litRegisterError.Text = "An error has occurred: " + result.Errors.FirstOrDefault();
    }

Authentication

In order to be able to authenticate users, we need to make use of two packages that we can install using NuGet.

  1. Using the same process you used to add the identity package, add the following packages
    1. Microsoft.AspNet.Identity.Owin
    2. Microsoft.Owin.Host.SystemWeb
  2. The next stage is to configure a startup class to ensure that the application knows how to authenticate users. Add a new item to the root of the project and choose the OWIN Startup class option, name the file Startup.cs. This will appear in the project with some existing code.
  3. Add the following using statements to the top of the file:
    using Microsoft.Owin.Security.Cookies;
    using Microsoft.AspNet.Identity;
  4. Add the following code inside the Configuration method so that the application uses Cookies for authentication:
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
    });
  5. Modify the code as follows (not forgetting the comma) to specify the location of the default login page:
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Login.aspx")
    });
    When a user tried to access a page for which they are not already authenticated, they will be redirected to Login.aspx in the root of the application - if you wish to use a differently named page or location, you can modify the path above.

The Login page

  1. To authenticate the user, we will need a login page. Add a web form to the project called Login.aspx
  2. Add text boxes with associated labels for username and password and add a button to submit those details. The code below assumes you have named the email and password text boxes txtLoginEmail and txtLoginPassword respectively
  3. Add a literal for displaying error messages, the code below assumes this is called litLoginError
  4. Add an event handler to the button you just added with the following code:
    var identityDbContext = new IdentityDbContext("IdentityConnectionString");
    var userStore = new UserStore<IdentityUser>(identityDbContext);
    var userManager = new UserManager<IdentityUser>(userStore);
    var user = userManager.Find(txtLoginEmail.Text, txtLoginPassword.Text);
    if (user != null)
    {
        //todo: log user in / instruct user to log in
    }
    else
    {
        litLoginError.Text = "Invalid username or password.";
    }
  5. The located user now needs authenticating, so add code as follows:
    private void LogUserIn(UserManager<IdentityUser> usermanager, IdentityUser user)
    {
        var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
        var userIdentity = usermanager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);
        authenticationManager.SignIn(new AuthenticationProperties() { }, userIdentity);
        //Note: user is automatically redirected if trying to access another page
    }
  6. Additionally add the following using statement to the top of the file:
    using Microsoft.Owin.Security;
  7. Go back and modify the code in the login button handler to call the LogUserIn method (there should be a comment identifying where this should be added). You will need to pass the usermanager and user items into the method.

The register-login process

You will have noticed that the register page doesn't automatically log the user in. It is down to you to decide whether to send the user to the login page, and allow them to log in, or whether to re-use some of the login page code to do this automatically. Using the login page has the advantage that the user gains some familiarity, but it is an additional step that the user must accomplish to achieve their goal.

Having decided what to do, implement the relevant code - it should be fairly clear how to do this based on the code you've written so far.

Log out

The following code will log a user out - consider where you want to button to permit this functionality to appear (for example only on restricted pages / on the master page etc.)

HttpContext.Current.GetOwinContext().Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);