Implementation of Cookie-Based Authentication in ASP.NET Without Identity

Introduction

Authentication is required for any web application in this advanced world, for security reasons. In Asp.net MVC, ASP.NET Identity is a complete package for handling authentication and authorization out of the box but there are scenarios where we might not need that complex and overloaded library, we can go with a simple custom solution, at least for my blog project. In this post, I demonstrate how to implement cookie-based authentication in an ASP.NET 8.0 application without using ASP.NET Identity.

If you want to see the plain cookie-based authentication demonstration without Asp.net identity in .net 8, check out this video tutorial.



Step 1: Setting Up the ASP.NET Core Project

First, create a new ASP.NET Core project. You can do this using the .NET CLI:

dotnet new web app -n CookieAuthApp cd CookieAuthApp

Step 2: Configuring Services

Next, configure the necessary services in the Startup.cs file. You'll need to add authentication and cookie services.


// Add services to the container. 
builder.Services.AddControllersWithViews(); 
// Configure authentication builder.Services.
AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) 
.AddCookie(options => { options.LoginPath = "/Account/Login"; 
options.LogoutPath = "/Account/Logout"; options.ExpireTimeSpan = TimeSpan.FromMinutes(30); 

Step 3: Creating a model

In this step, let's create a user model to interact with the view.


public class UserModel
{
public string Username { get; set; }
public string Password { get; set; }
public string Role { get; set; }
}

Step 4: Create a login view

Next, we will need a login view to show a form with username and password fields with a login button to the user.


<h2>Login</h2>

@if (ViewBag.ErrorMessage != null) {
  <p>@ViewBag.ErrorMessage</p>
}
<form method="post" asp-action="Login">
<div>
<label for="username">Username</label>
<input type="text" id="username" name="username" required />
</div><div>
<label for="password">Password</label>
<input type="password" id="password" name="password" required />
</div>
<button type="submit">Login</button>
</form>

Step 5: let's implement the controller-side logic

After the login view, we need HttpGet and HttpPost actions for login to show the login form to the user and receive the form data once the user clicks on the login button.


[HttpGet]
public IActionResult Login()
{
  return View();
}

[HttpPost]
public async Task Login(string username, string password)
{
  if (username == user.Username && password == user.Password)
  {
    var claims = new List
    {
        new Claim(ClaimTypes.Name, user.Username),
        new Claim(ClaimTypes.Role, user.Role) // Added role claim
    };
    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    var authProperties = new AuthenticationProperties
    {
        IsPersistent = true,
        ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(30)
    };
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
    return RedirectToAction("Index", "Home");
  }
ViewBag.ErrorMessage = "Invalid username or password";
return View();
}

[HttpPost]
public async Task Logout()
{
  await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
  return RedirectToAction("Login", "Account");
}

Step 6: Authorize annotation with role

The last step is to annotate the required controller with the Authorize attribute and we can also use the roles.


  [Authorize(Roles = "Admin")]
  [Route("Admin/[controller]")]

Conclusion

In this post, we've demonstrated how to implement cookie-based authentication in an ASP.NET Core application without using ASP.NET Identity. This approach suits simpler scenarios where you need more control over the authentication process. Remember always to consider security best practices when handling user authentication and data.