Authentication and Authorization are two major aspects while thinking about securing your application. Security is the main concern of modern applications because anyone can steal your data if it is not secured. So, if you are going to create an application where the data security is a primary concern, then think about Authentication and Authorization.


Authentication is the process to validate an anonymous user based on some credentials and Authorization process happens just after that and grants resources to this validated user. So, we can say, it's two-step validating process before providing the access of the resources or data.

We have many techniques to validate the users, like Windows Authentication, JWT Authentication, and Cookie Authentication etc. Today, we will learn how to implement and make ASP.NET Core MVC applications more secure using Cookie-based authentication and authorization. So, let's start the demonstration and create a fresh ASP.NET Core MVC project. You can refer to the following for the step by step process of creating an ASP.NET Core MVC application.

Be sure that while creating the project, your template should be Web Application (Model-View-Controller) and change the authentication as ‘No Authentication’.
You can download the code from here.

Here, you can choose the inbuilt Authentication functionality instead of ‘No Authentication’ and it will provide the readymade code. But we are choosing ‘No Authentication’ here because we are going to add our own Cookie-based authentication functionality in this demo and you will learn how to implement the Authentication and Authorization system from scratch.


We are choosing MVC template because we would like to see some Login and Logout functionality on UI along with Authentication and Authorization using Cookies. Now, click OK and it will take a few seconds and the project will be ready. Run it for checking if everything is working fine or not. Once everything is OK, you are ready to go.

Let’s move to the starting point of the ASP.NET Core application file which is “Startup.cs” where we configure the setting for the application like configuring the required services and configuring the middleware services etc. So, implementing the Authentication features, first, we have to add the authentication and then use it. So, let’s move to Startup.cs’s ConfigureService method and add the authentication feature using the following line of code, it will be just above services.AddMvc().
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();  

Now move to Configure in the startup.cs method and use the authentication features using the following line of code, it will be just above  routing.
app.UseAuthentication();  

Following is the whole code for adding the Authentication and using it.
    using Microsoft.AspNetCore.Authentication.Cookies;  
    using Microsoft.AspNetCore.Builder;  
    using Microsoft.AspNetCore.Hosting;  
    using Microsoft.AspNetCore.Http;  
    using Microsoft.AspNetCore.Mvc;  
    using Microsoft.Extensions.Configuration;  
    using Microsoft.Extensions.DependencyInjection;  
      
    namespace CookieDemo  
    {  
        public class Startup  
        {  
            public Startup(IConfiguration configuration)  
            {  
                Configuration = configuration;  
            }  
      
            public IConfiguration Configuration { get; }  
      
            // This method gets called by the runtime. Use this method to add services to the container.  
            public void ConfigureServices(IServiceCollection services)  
            {  
                services.Configure<CookiePolicyOptions>(options =>  
                {  
                    // This lambda determines whether user consent for non-essential cookies is needed for a given request.  
                    options.CheckConsentNeeded = context => true;  
                    options.MinimumSameSitePolicy = SameSiteMode.None;  
                });  
      
                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();  
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);  
            }  
      
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
            {  
                if (env.IsDevelopment())  
                {  
                    app.UseDeveloperExceptionPage();  
                }  
                else  
                {  
                    app.UseExceptionHandler("/Home/Error");  
                }  
      
                app.UseStaticFiles();  
                app.UseCookiePolicy();  
                app.UseAuthentication();  
                app.UseMvc(routes =>  
                {  
                    routes.MapRoute(  
                        name: "default",  
                        template: "{controller=Home}/{action=Index}/{id?}");  
                });  
            }  
        }  
    }  

We can implement Authentication through Login feature. In most of the applications today, Authorization is decided internally based on your role. So, now we are going to create account login and logout feature, so just create one more controller as ‘AccountController.cs’ inside the controllers folder and add two action methods, one for rendering the Login View and  the other one for posting user credentials data for logging in to the system. Here is the code for AccountController where we have implemented Login functionality.
    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Security.Claims;  
    using System.Threading.Tasks;  
    using Microsoft.AspNetCore.Authentication;  
    using Microsoft.AspNetCore.Authentication.Cookies;  
    using Microsoft.AspNetCore.Mvc;  
      
    namespace CookieDemo.Controllers  
    {  
        public class AccountController : Controller  
        {  
            public IActionResult Login()  
            {  
                return View();  
            }  
      
            [HttpPost]  
            public IActionResult Login(string userName, string password)  
            {  
                if(!string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(password))  
                {  
                    return RedirectToAction("Login");  
                }  
      
                //Check the user name and password  
                //Here can be implemented checking logic from the database  
      
                if(userName=="Admin" && password == "password"){  
      
                    //Create the identity for the user  
                    var identity = new ClaimsIdentity(new[] {  
                        new Claim(ClaimTypes.Name, userName)  
                    }, CookieAuthenticationDefaults.AuthenticationScheme);  
      
                    var principal = new ClaimsPrincipal(identity);  
      
                    var login = HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);  
      
                    return RedirectToAction("Index", "Home");  
                }  
      
                return View();  
            }  
        }  
    }  


The first login action method is rendering the UI for login page and once you fill the data required for Login as username and password then the second action method as Login will work and send the Post request to the server.

In this method, first, we will check whether username and password should not be empty then we will validate the username and password. Here, in this demonstration, we are checking the username and password with some dummy data. You can implement database login instead of this.

After validating the user information, if everything is correct then we create Identity for that user and create the cookie information for it. Based on this principal data, we try to Sign In using a generic function called "SignInAsync" and if everything goes in the right direction then we redirect to the Home page.

Now, let's create the Login view page from where we can give the functionality to the user to enter the username and password. So, right click on the Login action method and add view without a model. It will automatically create the Account folder inside the Views under that will create “login.cshtml” file. Just open it and create a container and add a form tag along with two textboxes for entering the username and password. Apart from this, create two separate buttons as “Submit” and “Reset”. Once you fill the data and click on the submit button, it will call to Login action method defined in Account Controller using POST call. So, modify the code of “login.cshtml” as follows.
    @{  
        ViewData["Title"] = "Login";  
    }  
      
    <div class="container">  
        <div class="row">          
            <div class="col-md-3">  
                <h2><strong>Login Page </strong></h2><br />  
                <form asp-action="login" method="post">  
                    <div class="form-group">  
                        <label>User Name</label>  
                        <input type="text" class="form-control" id="userName" name="userName" placeholder="Enter user name">  
                    </div>  
                    <div class="form-group">  
                        <label>Password</label>  
                        <input type="password" class="form-control" name="password" id="password" placeholder="Password">  
                    </div>  
                    <div class="form-check">  
                        <button class="btn btn-info" type="reset">Reset</button>  
                        <button type="submit" class="btn btn-primary">Submit</button>  
                    </div>  
                </form>  
            </div>  
        </div>  
    </div>  


So far we have implemented the Cookie-based Authentication functionality in Asp.Net Core MVC project. But what about Authorization. Authorization means, providing access to the authenticated user to access a resource based on role.

So, let's first understand how we can implement the Authorization in Asp.Net Core MVC. For now, if you will try to access the HOME page without sign in, you can access it. So, let’s prevent the anonymous user from accessing the HOME page directly, if someone wants to access the HOME page then they should have to go through the Authentication process and then they will be able to access it.

So, to accomplish this, let’s open the Home Controller and put the [Authorize] attribute just above to controller. You can place it at action level but here we would like to block the whole home controller functionality and if we want to access, just go and log in. So, just do something like below.
    using CookieDemo.Models;  
    using Microsoft.AspNetCore.Authorization;  
    using Microsoft.AspNetCore.Mvc;  
    using System.Diagnostics;  
      
    namespace CookieDemo.Controllers  
    {  
      
        [Authorize]  
        public class HomeController : Controller  
        {          
            public IActionResult Index()  
            {  
                return View();  
            }  
      
            public IActionResult About()  
            {  
                ViewData["Message"] = "Your application description page.";  
      
                return View();  
            }  
      
            public IActionResult Contact()  
            {  
                ViewData["Message"] = "Your contact page.";  
      
                return View();  
            }  
      
            public IActionResult Privacy()  
            {  
                return View();  
            }  
      
            [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]  
            public IActionResult Error()  
            {  
                return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });  
            }  
        }  
    }  


Note
Be sure you have cleared all cookies which have been  created based on your previous login. If you will not do this, you will be accessing the HOME page, it is because authenticated user cookie is available in browser memory.

So, let's check how it works. Run the application and try to access the Home page. You will see here that your application automatically redirects to Login page. Now let's try to provide the user information as username = "Admin" and password =" password". Once you will pass the correct credentials and login then you will redirect to HOME page. So, let'sadd the feature that shows the logged in username along with a logout button. If you click to the log out button, your cookie value will be deleted and you will redirect to login page.

So, let's open the Account Controller and add the following logout action method.
    [HttpPost]  
    public IActionResult Logout()  
    {  
          var login = HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);  
          return RedirectToAction("Login");  
    }  


And now open the Index.cshtml file from the Home folder inside the Views and modify the code as follows. Here, first of all, we are trying to show the Logged In username using @User.Identity.Name and apart from this adding a link for logout.
    @{  
        ViewData["Title"] = "Home Page";  
    }  
      
    <div class="container">  
        <div class="row">  
            <div class="col-md-12">  
                <h2><strong>Home Page </strong></h2><br /><br />  
                Hello @User.Identity.Name  
                <a asp-action="logout" asp-controller="account">  
                    Logout  
                </a>  
                <br />  
                <br />  
                <h4>Welcome to Asp.Net Core Authentication and Authorization Demo!!</h4>  
            </div>  
        </div>  
    </div>  


So far, we are able to understand how to implement Authentication in Asp.Net Core MVC and how to implement Authorization and give access to validate the users. Now, let's understand how to work with multiple roles. Here we are doing everything manually with some static value, but you can change the logic and connect to the database for validating the user. So, just modify the Login method as follows where we are providing two different kinds of roles; one is Admin role and another is User role. Based on these roles, we will provide access to some of the pages.
    [HttpPost]  
    public IActionResult Login(string userName, string password)  
    {  
        if (!string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(password))  
        {  
            return RedirectToAction("Login");  
        }  
      
        //Check the user name and password  
        //Here can be implemented checking logic from the database  
        ClaimsIdentity identity = null;  
        bool isAuthenticated = false;  
      
        if (userName == "Admin" && password == "password")  
        {  
      
            //Create the identity for the user  
            identity = new ClaimsIdentity(new[] {  
                        new Claim(ClaimTypes.Name, userName),  
                        new Claim(ClaimTypes.Role, "Admin")  
                    }, CookieAuthenticationDefaults.AuthenticationScheme);  
      
            isAuthenticated = true;  
        }  
      
        if (userName == "Peter" && password == "password")  
        {  
            //Create the identity for the user  
            identity = new ClaimsIdentity(new[] {  
                        new Claim(ClaimTypes.Name, userName),  
                        new Claim(ClaimTypes.Role, "User")  
                    }, CookieAuthenticationDefaults.AuthenticationScheme);  
      
            isAuthenticated = true;  
        }  
      
        if (isAuthenticated)  
        {  
            var principal = new ClaimsPrincipal(identity);  
      
            var login = HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);  
      
            return RedirectToAction("Index", "Home");  
        }  
        return View();  
    }  


Now let's move to HomeController and remove the [Authorize] attribute from the class level and put it in action level as follows. Here we have two different action methods which point to two different views. One is pointing to Index view and another one is pointing to the Setting page. Index page can be accessible to both type of roles, either it is Admin or User but the Setting page can be accessed only by Admin role.
    public class HomeController : Controller  
    {  
            [Authorize(Roles ="Admin, User")]  
            public IActionResult Index()  
            {  
                return View();  
            }  
      
            [Authorize(Roles ="Admin")]  
            public IActionResult Setting()  
            {  
                return View();  
      
            }  


Now modify the Index.cshtml file and add one thing as Role, just modify the code as follows.
    @{  
        ViewData["Title"] = "Setting Page";  
    }  
      
    <div class="container">  
        <div class="row">  
            <div class="col-md-12">  
                <h2><strong>Setting Page </strong></h2><br /><br />  
                Hello @User.Identity.Name !, Role @User.FindFirst(claim=>claim.Type==System.Security.Claims.ClaimTypes.Role)?.Value  
                <a asp-action="logout" asp-controller="account">  
                    Logout  
                </a>  
                <br />  
                <br />  
                <h4>Admin role user can only access this page!!</h4>  
            </div>  
        </div>  
    </div>  


Now, we have added everything and it's time to run the application. So, just press F5 and it will run your application. First, go to "Login" page and login with "User" role.

Once you will log in as a User role, definitely you will be redirected to the home page because the home page is accessible to both types  the roles.

Now, let's try to access the settings page, here you will get some Access Denied error. It is because "User" role member does not allow you to access the settings page. By default, you will get the following error as per the browser. But you can customize your error and page as well. It totally depends on you.

Now, let log out of the application for the "User" role and try to log in for Admin role. As follows, you can see, we are able to access the home page.

But let try to access the setting page for "Admin" role and yes, you will be accessed the setting page.

Lastly, let me show how you can see the cookie information. For this demo, I am using the Microsoft Edge browser, you can use any other as per your choice. But cookie information saves almost in the same place for every browser. So, just go to Network tab and then Cookie tab. Here you can see all the listed Cookies.