Skip to content

Instantly share code, notes, and snippets.

@zola-25
Last active January 28, 2024 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zola-25/5a814b7f1bf28840ee939ba45776c723 to your computer and use it in GitHub Desktop.
Save zola-25/5a814b7f1bf28840ee939ba45776c723 to your computer and use it in GitHub Desktop.
Maintaining User Session State with Cookies - Raw, Library-free Implementation with ASP.NET Core MVC
using System.Security.Cryptography;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace CookieSessionStateDemo.Controllers
{
public static class InMemoryDataStore
{
public static readonly Dictionary<string, string> UserSessions = new();
public static readonly Dictionary<string, string> UserCredentials = new() { { "user1", "password1" }, { "user2", "password2" } };
}
public class Credentials
{
public string Username { get; set; }
public string Password { get; set; }
}
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
string? sessionId = HttpContext.Request.Cookies["sessionId"];
bool isLoggedIn = sessionId != null && InMemoryDataStore.UserSessions.ContainsKey(sessionId);
if (isLoggedIn)
{
var username = InMemoryDataStore.UserSessions[sessionId!];
return View(model: username);
}
else
{
return RedirectToAction("Login");
}
}
[HttpGet("Login")]
public IActionResult Login()
{
return View();
}
[ValidateAntiForgeryToken]
[HttpPost("Login")]
public IActionResult LoginSubmit([FromForm] Credentials credentials)
{
string username = credentials.Username;
string password = credentials.Password;
if (InMemoryDataStore.UserCredentials.ContainsKey(username) && InMemoryDataStore.UserCredentials[username] == password)
{
string sessionId = GenerateSessionId();
InMemoryDataStore.UserSessions.Add(sessionId, username);
HttpContext.Response.Cookies.Append("sessionId", sessionId, new CookieOptions()
{
Secure = true,
HttpOnly = true,
SameSite = SameSiteMode.Strict,
Path = "/"
});
return RedirectToAction("Index");
}
else
{
return Unauthorized("Invalid username or password. Please try again.");
}
}
[ValidateAntiForgeryToken]
[HttpPost("Logout")]
public IActionResult Logout()
{
string? sessionId = HttpContext.Request.Cookies["sessionId"];
if (sessionId != null && InMemoryDataStore.UserSessions.ContainsKey(sessionId))
{
InMemoryDataStore.UserSessions.Remove(sessionId);
HttpContext.Response.Cookies.Delete("sessionId");
}
return RedirectToAction("Login");
}
string GenerateSessionId()
{
byte[] randomBytes = RandomNumberGenerator.GetBytes(32);
return Convert.ToBase64String(randomBytes);
}
}
}
@model string
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Restricted Page</title>
</head>
<body>
<h1>Restricted Home Page</h1>
Welcome @Model, you are authorized.
<h2>Logout?</h2>
<form method="post" asp-action="Logout" asp-controller="Home">
<button type="submit">Logout</button>
</form>
</body>
</html>
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Session Auth Cookie Login</title>
</head>
<body>
<h1>Login</h1>
<form method="post" asp-action="LoginSubmit" asp-controller="Home">
<label>
Username:
<input type="text" name="username" required>
</label>
<br>
<label>
Password:
<input type="password" name="password" required>
</label>
<br>
<button type="submit">Login</button>
</form>
</body>
</html>
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}");
app.Run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment