Using Custom Filter Attributes to Manage the Login Process in .NET Core with JWT

Published At 2025/Sep/02
No Image Found

In ASP.NET Core MVC, using a Custom Filter Attribute makes managing a logging system not only effortless but also incredibly powerful. Today, I’ll walk you through how to set this up in no time.

Building a Login Controller in ASP.NET Core MVC with Claims-Based Identity

  1. using Microsoft.AspNetCore.Authentication;
  2. using Microsoft.AspNetCore.Authentication.Cookies;
  3. using Microsoft.AspNetCore.Authorization;
  4. using Microsoft.AspNetCore.Diagnostics;
  5. using Microsoft.AspNetCore.Mvc;
  6. using OnlineCv.Factory.Users;
  7. using OnlineCv.Models;
  8. using OnlineCv.Models.ViewModel.RequestViewModel;
  9. using OnlineCv.Utility;
  10. using System.Diagnostics;
  11. using System.Security.Claims;
  12. namespace OnlineCv.Controllers
  13. {
  14. public class HomeController : Controller
  15. {
  16. private readonly ILogger<HomeController> _logger;
  17. private readonly IUserFactory _userFactory;
  18. private readonly IUtility _utility;
  19. public HomeController(ILogger<HomeController> logger,
  20. IUserFactory userFactory,
  21. IUtility utility)
  22. {
  23. _logger = logger;
  24. _userFactory = userFactory;
  25. _utility = utility;
  26. }
  27. [AllowAnonymous]
  28. public IActionResult Login()
  29. {
  30. return View(new LoginViewModel());
  31. }
  32. [AllowAnonymous]
  33. [HttpPost]
  34. public async Task<IActionResult> Login(LoginViewModel loginViewModel)
  35. {
  36. var user = await _userFactory.GetUserByCredential(loginViewModel.Email,loginViewModel.Password);
  37. if (user is not null)
  38. {
  39. ClaimsIdentity identity = null;
  40. identity = new ClaimsIdentity(new[] {
  41. new Claim(ClaimTypes.Email,loginViewModel.Email),
  42. new Claim(ClaimTypes.Role,Constent.Roles[0])
  43. }, CookieAuthenticationDefaults.AuthenticationScheme);
  44. var principal = new ClaimsPrincipal(identity);
  45. if(HttpContext.Session.Keys.Contains("userId"))
  46. HttpContext.Session.Remove("userId");
  47. if (HttpContext.Session.Keys.Contains("token"))
  48. HttpContext.Session.Remove("token");
  49. await HttpContext.SignOutAsync(Constent.Roles[0]);
  50. await HttpContext.SignInAsync(Constent.Roles[0], principal);
  51. HttpContext.Session.SetString("userId", user.Id.ToString());
  52. var token = _utility.GenerateToken(loginViewModel.Email, user.Id.ToString(), "User");
  53. HttpContext.Session.SetString("token", token);
  54. return RedirectToAction(controllerName: "Resume", actionName: "BasicInfo");
  55. }
  56. ModelState.AddModelError(string.Empty,"Login Failed");
  57. return View();
  58. }
  59. public IActionResult Registration()
  60. {
  61. return View(new RegistrationViewModel());
  62. }
  63. [HttpPost]
  64. public async Task<IActionResult> Registration(RegistrationViewModel registrationViewModel)
  65. {
  66. if (ModelState.IsValid)
  67. {
  68. var res = await _userFactory.UserRegistration(registrationViewModel);
  69. ViewBag.Result = res.success;
  70. ViewBag.Message = res.message;
  71. }
  72. return View();
  73. }
  74. }
  75. }

Middleware

  1. builder.Services.AddAuthentication(options =>
  2. {
  3. options.DefaultScheme = Constent.Roles[0];
  4. }).AddCookie(Constent.Roles[0], options =>
  5. {
  6. options.Cookie.Name = Constent.Roles[0]+".Says";
  7. options.LoginPath = "/Home/Login";
  8. });
  9. builder.Services.AddDistributedMemoryCache();
  10. builder.Services.AddSession(options =>
  11. {
  12. options.Cookie.Name = ".Online.Cv.Session";
  13. options.IdleTimeout = TimeSpan.FromHours(1);
  14. options.Cookie.IsEssential = true;
  15. });

Get User Token

  1. public string GenerateToken(string email, string userId, string role)
  2. {
  3. var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Constent.Key));
  4. var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
  5. var secToken = new JwtSecurityToken(
  6. signingCredentials: credentials,
  7. issuer: Constent.Issuer,
  8. audience: Constent.Audiunce,
  9. claims: new[]
  10. {
  11. new Claim(JwtRegisteredClaimNames.Sub, email),
  12. new Claim(ClaimTypes.Role, role),
  13. new Claim("userId", userId)
  14. },
  15. expires: DateTime.UtcNow.AddHours(1));
  16. var handler = new JwtSecurityTokenHandler();
  17. return handler.WriteToken(secToken);
  18. }

Make sure you have assigned Middleware Methods as well

  1. app.UseAuthentication();
  2. app.UseAuthorization();
  3. app.UseSession();

Custom Filter Attribute

  1. public class AuthenticationAttribute : Attribute, IAsyncActionFilter
  2. {
  3. public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
  4. {
  5. var token = context.HttpContext.Session.GetString("token");
  6. var userId = context.HttpContext.Session.GetString("userId");
  7. if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(userId))
  8. {
  9. context.Result = new RedirectToActionResult(actionName: "Login", controllerName: "Home", routeValues: "");
  10. return;
  11. }
  12. if (!ValidateToken(token.ToString()).success)
  13. {
  14. context.Result = new RedirectToActionResult(actionName: "Login", controllerName: "Home", routeValues: "");
  15. return;
  16. }
  17. if (!ValidateUser(token, userId).success)
  18. {
  19. context.Result = new RedirectToActionResult(actionName: "Login", controllerName: "Home", routeValues: "");
  20. return;
  21. }
  22. await next();
  23. }
  24. private (bool success, string message) ValidateToken(string authToken)
  25. {
  26. var tokenHandler = new JwtSecurityTokenHandler();
  27. var validationParameters = GetValidationParameters();
  28. SecurityToken validatedToken;
  29. try
  30. {
  31. IPrincipal principal = tokenHandler.ValidateToken(authToken, validationParameters, out validatedToken);
  32. }
  33. catch (Exception e)
  34. {
  35. return (false,e.Message);
  36. }
  37. return (true,"Token Verified");
  38. }
  39. private (bool success, string? userId, string message) ValidateUser(string authToken, string userId)
  40. {
  41. var tokenHandler = new JwtSecurityTokenHandler();
  42. var key = Encoding.UTF8.GetBytes(Constent.Key);
  43. var tokenValidationParameters = GetValidationParameters();
  44. ClaimsPrincipal principal;
  45. try
  46. {
  47. principal = tokenHandler.ValidateToken(authToken, tokenValidationParameters, out _);
  48. }
  49. catch (SecurityTokenException ex)
  50. {
  51. return (false, null, ex.Message);
  52. }
  53. var userIdClaim = principal.FindFirst("userId");
  54. if (userIdClaim == null)
  55. return (false, null, "User not found");
  56. return (userIdClaim.Value.ToLower()==userId.ToLower(), userIdClaim.Value, "user found");
  57. }
  58. private TokenValidationParameters GetValidationParameters()
  59. {
  60. return new TokenValidationParameters()
  61. {
  62. ClockSkew = TimeSpan.Zero,
  63. ValidIssuer = Constent.Issuer,
  64. ValidAudience = Constent.Audiunce,
  65. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Constent.Key))
  66. };
  67. }
  68. }

Useage of Custom Filter Attribute

  1. //Microsoft Default Singin Management Attribute
  2. [Authorize(Roles = "User", AuthenticationSchemes = "User")]
  3. //Custom Attribue
  4. [Authentication]