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.
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.
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.
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.
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" />
Identity can be installed as a package by using the NuGet package manager built into Visual Studio:
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
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.
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.
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
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();
}
In order to be able to authenticate users, we need to make use of two packages that we can install using NuGet.
using Microsoft.Owin.Security.Cookies;
using Microsoft.AspNet.Identity;
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
});
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.
txtLoginEmail
and txtLoginPassword
respectivelylitLoginError
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.";
}
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
}
using Microsoft.Owin.Security;
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.
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);