Authentication and Authorization are two major aspects while thinking about securing your application. Security is the main concern of modern application and nobody want to use security less application because anyone can steal your data if it is not secured. So, if you are going to create an application where data security is a primary concern then think about Authentication and Authorization.
Authentication is the process to validate the anonymous user based on some credentials and Authorization process happens just after that and grant to resources to this validate user. So, we can say, it's two steps validating process before providing the access of the resource or data.
We have many techniques to validate users like Windows Authentication, JWT Authentication, Cookie Authentication etc. Today, we will learn how to implement and make Asp.Net Core MVC application more secure using Cookie based authentication and authorization. So, let's start the demonstration and create the fresh Asp.Net Core MVC project. You can refer following for step by step information to create Asp.Net Core MVC application.
First Application in Asp.Net Core MVC 2.0
Be sure while creating the project, your template should be Web Application (Model-View-Controller) and change the authentication as ‘No Authentication’.
Here you can choose the inbuilt Authentication functionality instead of ‘No Authentication’ and it will provide 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 the 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 Cookie. Now click to OK and it will take a few seconds and project will be ready. Run it for checking if everything is working fine or not. Once everything will be OK, you are ready to go.
Let’s move to start point of 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 to services.AddMvc().
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
Now move to Configure in startup.cs method and use the authentication features using the following line of code, it will be just above before using 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 as we can see in today's most of the application and Authorization decides 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 another one is for posting user credentials data for login 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 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 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, till now 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 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 to access 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 action level but here we would like block whole home controller functionality and if 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 });
}
}
}
So, let 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 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 add the feature that shows the logged in username along with a logout button. If you click to log out button, your cookie value will be deleted and you will redirect to login page.
So, let 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 users. Now, let understand how to work with multiple roles. Here everything we are doing 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 role, one is Admin role and another is User role. Based on these roles, we will provide the access of 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 == "Mukesh" && 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 move to HomeController and remove the [Authorize] attribute from the class level and put it action level as follows. Here we have two different action method which pointing to two different views. One is pointing to Index view and another one is pointing to Setting page. Index page can be accessible to both type of role, either it is Admin or User but Setting page can access 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 with as a User role, definitely you will be redirected to the home page because the home page is accessible to botht ypese of the role.
Now, let try to access the setting page, here you will get some Access Denied error. It is because "User" role member does not allow to access setting page. By default, you will get the following error as per browser. But you can customize your error and page as well. It totally depends on you.
Now, let log out the application for "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.
At the last, 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 same places for every browser. So, just go to Network tab and then Cookie tab. Here you can see all the listed Cookies.
Conclusion
So, today we have learned what authentication and authorization are and how to implement the Cookie Based Authentication and Authorization in Asp.Net Core MVC.
I hope this post will help you. Please put your feedback using comment which helps me to improve myself for next post. If you have any doubts please ask your doubts or query in the comment section and If you like this post, please share it with your friends. Thanks
Posted Comments :
Joseph Posted : 5 Years Ago
Hi Kumar, This is a very good tutorial. Could you send me the complete project file, please? Getting some errors when logging out. Thanks Regards Joseph
ra Posted : 3 Years Ago
abcd
Joshua Posted : Last Year
Hi sir , thank you for the article. If you include sso it will be very helpful for us. Thank you
Tuan Posted : Last Year
In your code, I do not see about service.AddDataProtection.
Kolli Posted : 5 Years Ago
Thanks for sharing. Nice article.