How to do Authentication of Users in ASP.NET Core Identity

How to do Authentication of Users in ASP.NET Core Identity

Authentication is the process of establishing the identity of a user. The users presents their credentials (username & password) to the application. The username is public information but the password is known only by the user. The application is able to authenticate the user only when the correct credentials are provided to it through the login page.

Also check my previous Identity tutorial – Username, Email & Password Policy in ASP.NET Core Identity.

How Authentication works in ASP.NET Core Identity

Let us create the Authentication feature in ASP.NET Core Identity. So first create a new Controller called HomeController.cs and change it’s Index Action to return a string Hello as a Model to the default view:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace Identity.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View((object)"Hello");
        }
    }
}

Next, add Index View inside the Views ➤ Home folder with the following code:

@model string
 
<h1 class="bg-info text-white">Index</h1>
@Model

The View does nothing special except for showing the string Hello which is returned by the Controller.

Now run your project and you will see the Hello message displayed on your browser, see below image:

Index view displayed without authentication

There is no restriction for invoking the Index Action method at present. Therefore when I ran the project then the browser sent an un-authenticated request to this action method. This un-authenticated request was able to invoke this action method and I see the Hello message on my browser.

Now I will restrict the Index Action so that it can only be invoked by requests that comes from Authenticated Users. So add the [Authorize] attribute, which resides on the Microsoft.AspNetCore.Authorization namespace, on the Index action method:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Identity.Controllers
{
    public class HomeController : Controller
    {
        [Authorize]
        public IActionResult Index()
        {
            return View((object)"Hello");
        }
    }
}

Now run your project once again, and this time you will see a message stating – The localhost page can’t be found. HTTP ERROR 404. This is shown by the image below:

HTTP ERROR 404

There are 2 things that happened here:

  • 1. I applied the [Authorize] attribute to the Index Action so my un-authenticated request was not able to invoke it.
  • 2. The Identity redirected me to the Login action of the Account controller which is the default login address in Identity and it’s URL is – https://localhost:44395/Account/Login?ReturnUrl=%2F. Here in this page I can log in to the application. I will construct this page in a moment.

Notice the URL contains the query string variable called ReturnUrl which contains %2F. Once I complete my log in procedure then I will be redirected to the URL http://localhost:44395.

Note: %2F is an encoded URL which stands for /.

Changing the Default Login URL in Identity

Although /Account/Login is the default Login URL in Identity, and here users are redirected when authorization is required.

If you want to change this login URL then go to in the ConfigureServices() method of the Startup class. There add the below code to it:

services.ConfigureApplicationCookie(opts => opts.LoginPath = "/Authenticate/Login")

Here I have specified the new login URL as /Authenticate/Login i.e https://localhost:44395/Authenticate/Login will be in my case (port may differ for yours). Note that this ULR cannot be formed by the routes so if you change your routing scheme then you should make sure that you change the Identity Login URL manually here.

Implementing Authentication in Identity

In order to create a login feature, I need to create a Login.cs class inside the Models folder. This class has 3 properties – Email, Password and ReturnUrl.

Email and Password properties are made Required fields since User will have to enter both of them while login. The ReturnUrl property will contains the Return URL set by the Identity System.

The Login.cs class code is given below:

using System.ComponentModel.DataAnnotations;

namespace Identity.Models
{
    public class Login
    {
        [Required]
        public string Email { get; set; }

        [Required]
        public string Password { get; set; }

        public string ReturnUrl { get; set; }
    }
}

The Identity redirects users to the Login URL which is https://localhost:44395/Account/Login. Therefore I need to create the Account controller having Login action method so that the users can do the log in step.

So create the AccountController.cs class in the Controllers folder with the following code:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Identity.Models;
using System.Threading.Tasks;

namespace Identity.Controllers
{
    [Authorize]
    public class AccountController : Controller
    {
        private UserManager<AppUser> userManager;
        private SignInManager<AppUser> signInManager;

        public AccountController(UserManager<AppUser> userMgr, SignInManager<AppUser> signinMgr)
        {
            userManager = userMgr;
            signInManager = signinMgr;
        }

        public IActionResult Index()
        {
            return View();
        }

        [AllowAnonymous]
        public IActionResult Login(string returnUrl)
        {
            Login login = new Login();
            login.ReturnUrl = returnUrl;
            return View(login);
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Login(Login login)
        {
            if (ModelState.IsValid)
            {
                AppUser appUser = await userManager.FindByEmailAsync(login.Email);
                if (appUser != null)
                {
                    await signInManager.SignOutAsync();
                    Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(appUser, login.Password, false, false);
                    if (result.Succeeded)
                        return Redirect(login.ReturnUrl ?? "/");
                }
                ModelState.AddModelError(nameof(login.Email), "Login Failed: Invalid Email or password");
            }
            return View(login);
        }
    }
}
Explanation of the Codes

The controller class is applied with an [Authorize] attribute so that it cannot be invoked by un-authenticated requests. However I have added [AllowAnonymous] attributes to the Login Action Methods so that these action methods can be invoked by un-authenticated requests.

See I have added a dependency of UserManager<AppUser> & SignInManager<AppUser> in the constructor of the controller so these objects will be provided by the Dependency Injection feature of ASP.NET Core.

The associated code is given below:

private UserManager<AppUser> userManager;
private SignInManager<AppUser> signInManager;
 
public AccountController(UserManager<AppUser> userMgr, SignInManager<AppUser> signinMgr)
{
    userManager = userMgr;
    signInManager = signinMgr;
}

The UserManager is used to manage Users in Identity while the SignInManager is used to perform the authentication of the users.

Next, I added the HTTP GET version of the Login action method. I applied the [AllowAnonymous] attribute on it so that it does not require authentication. This is obvious otherwise users will not be able to perform login.

This action has a returnUrl variable in the parameter whose value is provided from the ReturnUrl variable of the query sting by the Model Binding technique of ASP.NET Core.

The action method code is:

[AllowAnonymous]
public IActionResult Login(string returnUrl)
{
    Login login = new Login();
    login.ReturnUrl = returnUrl;
    return View(login);
}

The action return Login class object as model to the view. Notice I have set the value of the ReturnUrl property of the Login class to the value that comes to the action’s parameter.

Next, I have added the POST version of the Login Action method where the actual authentication of the user will be performed. The action method code is:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(Login login)
{
    if (ModelState.IsValid)
    {
        AppUser appUser = await userManager.FindByEmailAsync(login.Email);
        if (appUser != null)
        {
            await signInManager.SignOutAsync();
            Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(appUser, login.Password, false, false);
            if (result.Succeeded)
                return Redirect(login.ReturnUrl ?? "/");
        }
        ModelState.AddModelError(nameof(login.Email), "Login Failed: Invalid Email or password");
    }
    return View(login);
}

This action method has a parameter, of type Login class, through which it receives the login values (i.e. email & password) filled by the user in the login form given on the Login View. The method is provided with 2 attributes which are:

1. [AllowAnonymous] attribute allows it to be invoked by un-authenticated requests.
2. [ValidateAntiForgeryToken] to prevent cross-site request forgery.

First I get the User’s details from the FindByEmailAsync() method of the UserManager class. This method takes the email address which is provided by the user on the login form. See below code:

AppUser appUser = await userManager.FindByEmailAsync(login.Email);

Next, I check if the user details which is received on the AppUser object is not null. In that case I am first signing out any logged in user from the application:

await signInManager.SignOutAsync();

Then I am using the PasswordSignInAsync method of the SignInManager class to log in the user by providing with the AppUser object and the password contained in the login.Password property.

Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(appUser, login.Password, false, false);

I have provided false values for both last 3rd and 4th parameters because I don’t want a persistence cookie for a persistence login (that remain even after closing the browser), nor I want to lock on the account when sign-in fails.

This method returns SignInResult object that contains the result of the sign-in procedure. It’s Succeeded property contains true value if the sign-in is successful else contains false.

Finally, I check if the value of the Succeeded property is true. In that case I am returning the user to the URL contained in the ReturnUrl property of the Login class. The code which does this work is:

if (result.Succeeded)
    return Redirect(login.ReturnUrl ?? "/");

I also need the Login View which will contain the Login form. From this form the users will do the login to their accounts. So create the Login view inside the Views/Account folder with the code as shown below:

@model Login
 
<h1 class="bg-info text-white">Login</h1>
<div class="text-danger" asp-validation-summary="All"></div>
 
<form asp-action="Login" method="post">
    <input type="hidden" asp-for="ReturnUrl" />
    <div class="form-group">
        <label asp-for="Email"></label>
        <input asp-for="Email" class="form-control" />
    </div>
    <div class="form-group">
        <label asp-for="Password"></label>
        <input asp-for="Password" class="form-control" />
    </div>
    <button class="btn btn-primary" type="submit">Log In</button>
</form>

It’s time to test the authentication feature. I already have a user with the following details:

1. Name – tom
2. Email – [email protected]
3. Password – [email protected]

I will login in with this user’s credentials.

If you don’t have any User then you can create it from the URL – https://localhost:44395/Admin/Create. The project download link is given at the end of the tutorial.

Run your project, and when you are redirected to the Login page, add the following information to the login form:
1. Email – [email protected]
2. Password – wrongpass

On clicking the Log In button you will see the message – Login Failed: Invalid Email or password. This is because I entered the wrong password, see the below image:

Authentication Failed in Identity

Now enter the correct password and click the Log In button. You will find the authentication is successful this time and you will be redirected to the Home controller’s Index view where you will see the Hello message:

Index view displayed with authentication

Showing Logged in User’s name

I can also show the currently logged-in user’s name onn the view. I can fetch the current user’s info from the GetUserAsync() method of the UserManager class as shown below.

AppUser user = await userManager.GetUserAsync(HttpContext.User);

So edit the Home Controller’s code to fetch the user and send his name to the view. I have shown this code in highlighted way.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Identity.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace Identity.Controllers
{
    public class HomeController : Controller
    {
        private UserManager<AppUser> userManager;
        public HomeController(UserManager<AppUser> userMgr)
        {
            userManager = userMgr;
        }

        [Authorize]
        public async Task<IActionResult> Index()
        {
            AppUser user = await userManager.GetUserAsync(HttpContext.User);
            string message = "Hello " + user.UserName;
            return View((object)message);
        }
    }
}

Now the user’s name will be shown on the view as shown by the below image:

Logged-in user name Identity

Logout Feature in Identity

The Logout feature will simply logout the signed user from Identity. I have already created a Login feature for users, now I will create Logout feature. So add the Logout action method to the AccountController.cs with the following code:

public async Task<IActionResult> Logout()
{
    await signInManager.SignOutAsync();
    return RedirectToAction("Index", "Home");
}

The Logout Action is fairly simple which just uses signInManager.SignOutAsync() to do the sign-out of any logged in user from the application.

Create Multi-Language websites in ASP.NET Core without any difficulty. Check my tutorial Globalization and Localization with Resource Files in ASP.NET Core

The Logout Action method will be linked from the Home Controller’s Index View with an anchor tag.

Update the Index Action of the Home Controller like shown below:

@model string
 
<h1 class="bg-info text-white">Index</h1>
@Model
 
@if (User?.Identity?.IsAuthenticated ?? false)
{
    <a asp-controller="Account" asp-action="Logout" class="btn btn-danger">Logout</a>
}

Here, I have used the RazorPageBase class of the Microsoft.AspNetCore.Mvc.Razor namespace. This class’s User.Identity.IsAuthenticated property gives true if the user is logged in else returns null. I have used it to show my Logout link only when the user is logged in to the application.

Run your project and log-in with any user’s account. After login you will be redirected to the home page where you will see the Logout button. Click it and you will be logged out from Identity. See the below image:

logout feature identity

Once the User is authenticated then Identity will store a cookie in your browser. This cookie name is .AspNetCore.Identity.Application. You can see this cookie in the Application tab of your Chrome browser’s developer tools. See the below image:

identity cookie

This cookie is sent to the server at each & every HTTP Request, like when you open any URL of your application in your browser. The ASP.NET Core Identity uses this cookie to determine whether the user is authenticated or not.

Note – To logout any user from Identity, simple delete this cookie by selecting this cookie and clicking the ‘X’ sign.

You can set the expiry time of the Identity Cookie by using the ConfigureApplicationCookie method of IServiceCollection interface.

Add the below code to the ConfigureServices() method of the Startup class to set the expiry time to 20 minutes in sliding expiry way.

services.ConfigureApplicationCookie(options =>
{
    options.Cookie.Name = ".AspNetCore.Identity.Application";
    options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
    options.SlidingExpiration = true;
});

You can download the full codes of this tutorial from the below link:

Download

Conclusion
This completes this tutorial on Authenticating Users in Identity and now you are in a position to create your own secured areas in your website, where there will be a need to do login and logout.

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "ASP.NET Core, jQuery, EF Core, SEO, jQuery, HTML" and more.