Introduction
This article explains how to log in with JWT (json web token) and set custom authentication for every role logged in into the web application in ASP.NET Core 3.1.
So, for login, we will see how to get a JWT token with user claims and store it in the session storage key “JWToken”, then apply the authentication filter by Role, assign it to that user and restrict to another user unauthorized user and how to logout users.
Overview
JWT-(Json Web Token)
- JWToken is the JSON Format string value.
-
JWToken is issued for each valid user and created once during user login.
-
JWToken is used for HTTP requests and is valid until the user logs out.
Authentication- Authentication is the process of determining who you are.
Claims-based authentication
Claims are a statement about or a property of a particular identity. That consists of name and value for ex. You could have UserName claim, EmailAddress claim, or Role claim.
- This is a single identity that contains a no. of claims.
Let’s start with an example:
Step 1
Create an ASP.NET Core web application with MVC in .NET Core 3.1.
Step 2
Create Login Controller.cs and make a login view over the index action.
- public class LoginController : BaseController
- {
- ApplicationDbContext db;
- public LoginController(ApplicationDbContext db)
- {
- this.db = db;
- }
- [HttpGet, AllowAnonymous]
- public IActionResult Index()
- {
- return View();
- }
- }
Step 3
Create a BaseController.cs and create an asynced "CreateAuthenticationTicket " function.
- public class BaseController : Controller
- {
- public async Task CreateAuthenticationTicket(AdminLogin user)
- {
- var key = Encoding.ASCII.GetBytes(SiteKeys.Token);
- var JWToken = new JwtSecurityToken(
- issuer: SiteKeys.WebSiteDomain,
- audience: SiteKeys.WebSiteDomain,
- claims: GetUserClaims(user),
- notBefore: new DateTimeOffset(DateTime.Now).DateTime,
- expires: new DateTimeOffset(DateTime.Now.AddDays(1)).DateTime,
- signingCredentials: new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
- );
- var token = new JwtSecurityTokenHandler().WriteToken(JWToken);
- HttpContext.Session.SetString("JWToken", token);
- }
- private IEnumerable<Claim> GetUserClaims(AdminLogin user)
- {
- List<Claim> claims = new List<Claim>();
- Claim _claim;
- _claim = new Claim(ClaimTypes.Name, user.UserName);
- claims.Add(_claim);
- _claim = new Claim("Role", Role.Admin);
- claims.Add(_claim);
- return claims.AsEnumerable<Claim>();
- }
- }


Create a Role struct in BaseController.cs and set different roles under this.
- public struct Role
- {
- public const string Admin = "Admin";
- public const string Guest = "Guest";
- }
SiteKeys.cs
- using Microsoft.Extensions.Configuration;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- namespace DemoIntro.Models
- {
- public class SiteKeys
- {
- private static IConfigurationSection _configuration;
- public static void Configure(IConfigurationSection configuration)
- {
- _configuration = configuration;
- }
- public static string WebSiteDomain => _configuration["WebSiteDomain"];
- public static string Token => _configuration["Secret"];
- }
- }
Now create the Login Post method
- [HttpPost, AllowAnonymous]
- public IActionResult LoginNow(AdminLogin model)
- {
- var admin = db.AdminLogin.Where(x => x.UserName.Trim() == model.UserName.Trim() && x.Password ==model.Password).FirstOrDefault();
- try
- {
- if (admin != null)
- {
- _ = CreateAuthenticationTicket(admin);
- // Show Success Message -"Welcome!"
- return RedirectToAction(nameof(ProfileController.CreateEditProfile), "Profile");
- }
- else
- {
- // Show Error Message- "Invalid Credentials."
- return View("Index", model);
- }
- }
- catch (Exception ex)
- {
- //Show Error Message- ex.Message
- return View("Index", model);
- }
- }
Step 5
Create index.cshtml
- @model DemoIntro.Data.Tables.AdminLogin
- @{
- Layout = null;
- }
- <!DOCTYPE html>
- <html>
- <head>
- </head>
- <body class="hold-transition login-page">
- <div class="login-box">
- <div class="card">
- <div class="card-body login-card-body">
- <p class="login-box-msg">Sign in to start your session</p>
- <form id="frmLogin" asp-action="LoginNow" asp-controller="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post">
- <div class="form-group">
- <div class="input-group mb-3">
- <input asp-for="@Model.UserName" class="form-control" placeholder="Email">
- <div class="input-group-append">
- <div class="input-group-text">
- <span class="fas fa-envelope"></span>
- </div>
- </div>
- </div>
- <span asp-validation-for="@Model.UserName" class="text-danger"></span>
- </div>
- <div class="form-group">
- <div class="input-group mb-3">
- <input asp-for="@Model.Password" class="form-control" placeholder="Password">
- <div class="input-group-append">
- <div class="input-group-text">
- <span class="fas fa-lock"></span>
- </div>
- </div>
- </div>
- <span asp-validation-for="@Model.Password" class="text-danger"></span>
- </div>
- <div class="row">
- <!-- /.col -->
- <div class="col-4">
- <button type="submit" class="btn btn-primary btn-block">Sign In</button>
- </div>
- <!-- /.col -->
- </div>
- </form>
- </div>
- <!-- /.login-card-body -->
- </div>
- </div>
- </body>
- </html>
Step 6
Set a few JWT authentication tags in Startup.cs file. services.AddAuthentication ,services.AddSession
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddDbContext<ApplicationDbContext>(options =>
- options.UseSqlServer(
- Configuration.GetConnectionString("DefaultConnection")));
- services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
- .AddEntityFrameworkStores<ApplicationDbContext>();
- services.AddControllersWithViews();
- services.AddRazorPages();
- #region "JWT Token For Authentication Login"
- SiteKeys.Configure(Configuration.GetSection("AppSettings"));
- var key = Encoding.ASCII.GetBytes(SiteKeys.Token);
- services.AddSession(options =>
- {
- options.IdleTimeout = TimeSpan.FromMinutes(60);
- });
- services.AddAuthentication(auth =>
- {
- auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
- auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
- })
- .AddJwtBearer(token =>
- {
- token.RequireHttpsMetadata = false;
- token.SaveToken = true;
- token.TokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuerSigningKey = true,
- IssuerSigningKey = new SymmetricSecurityKey(key),
- ValidateIssuer = true,
- ValidIssuer = SiteKeys.WebSiteDomain,
- ValidateAudience = true,
- ValidAudience = SiteKeys.WebSiteDomain,
- RequireExpirationTime = true,
- ValidateLifetime = true,
- ClockSkew = TimeSpan.Zero
- };
- });
- #endregion
- }
Add JWToken in Authorization Bearer in the request header:
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- app.UseDatabaseErrorPage();
- }
- else
- {
- app.UseExceptionHandler("/Home/Error");
- // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
- app.UseHsts();
- }
- app.UseHttpsRedirection();
- app.UseStaticFiles();
- app.UseRouting();
- #region "JWT Token For Authentication Login"
- app.UseCookiePolicy();
- app.UseSession();
- app.Use(async (context, next) =>
- {
- var JWToken = context.Session.GetString("JWToken");
- if (!string.IsNullOrEmpty(JWToken))
- {
- context.Request.Headers.Add("Authorization", "Bearer " + JWToken);
- }
- await next();
- });
- app.UseAuthentication();
- app.UseAuthorization();
- #endregion
- app.UseEndpoints(endpoints =>
- {
- //Routing Area Admin
- endpoints.MapAreaControllerRoute(
- name: "routeArea",
- areaName: "Admin",
- pattern: "Admin/{controller=Home}/{action=Index}/{id?}");
- endpoints.MapRazorPages();
- //Routing Front
- endpoints.MapControllerRoute(
- name: "default",
- pattern: "{controller=Main}/{action=Index}/{id?}");
- endpoints.MapRazorPages();
- });
- }

Step 7
Add connection and configurations in the appsettings.json file.
- {
- "ConnectionStrings": {
- "DefaultConnection": "Server=LOKESH007\\LOKESH007;Database=DemoIntro;user=sa;password=admin@1234;Trusted_Connection=False;"
- },
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
- }
- },
- "AllowedHosts": "*",
- "AppSettings": {
- "Secret": "WriteMySecretKeyForAuthentication",
- "WebSiteDomain": "http://localhost/Demo/",
- "WebSiteName": "khushbu Saini"
- }
- }
Step 8
Now create our custom Authorize filter validating each user role, restrict unauthorized users, auto redirect to login if session timeout or unauthorized request hit.
Authorize.cs
- using Microsoft.AspNetCore.Http;
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.AspNetCore.Mvc.Filters;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Security.Claims;
- using System.Threading.Tasks;
- namespace DemoIntro.filters
- {
- public class AuthorizeAttribute : TypeFilterAttribute
- {
- public AuthorizeAttribute(params string[] claim) : base(typeof(AuthorizeFilter))
- {
- Arguments = new object[] { claim };
- }
- }
- public class AuthorizeFilter : IAuthorizationFilter
- {
- readonly string[] _claim;
- public AuthorizeFilter(params string[] claim)
- {
- _claim = claim;
- }
- public void OnAuthorization(AuthorizationFilterContext context)
- {
- var IsAuthenticated = context.HttpContext.User.Identity.IsAuthenticated;
- var claimsIndentity = context.HttpContext.User.Identity as ClaimsIdentity;
- if (IsAuthenticated)
- {
- bool flagClaim = false;
- foreach (var item in _claim)
- {
- if (context.HttpContext.User.HasClaim("Role", item))
- flagClaim = true;
- }
- if (!flagClaim)
- {
- if (context.HttpContext.Request.IsAjaxRequest())
- context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; //Set HTTP 401
- else
- context.Result = new RedirectResult("~/Login/Index");
- }
- }
- else
- {
- if (context.HttpContext.Request.IsAjaxRequest())
- {
- context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; //Set HTTP 403 -
- }
- else
- {
- context.Result = new RedirectResult("~/Login/Index");
- }
- }
- return;
- }
- }
- }

Step 9
Set the access role to each user controller
- [Authorize(Role.Admin)]
- public class AchievementsController : BaseController
- {
- ////
- }
- [Authorize(Role.Guest)]
- public class AccessoriesController : BaseController
- {///
- }
Step 10
Finally, the logout function for each use logout is here:
- [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
- public IActionResult Logout()
- {
- HttpContext.Session.Clear();
- return RedirectToAction("Index");
- }
Output
Here is the login page, I have the first login with the admin. It shows me successful login and redirects to the admin dashboard.

Now, click on Accessories Controller. Because I have provided the access of this controller to Guest only, the admin can't unable to access it and auto-redirect to login view.

Summary
In this article, I discussed how we can get log in with multiple identity claim users. We also saw how we create our custom authentication filter so that we can custom authenticate each user while logging in and also validate that user role. Furthermore, we saw how to restrict other unauthorized users for login and also restrict them with URL rewriting. At last, we saw how to log out.

Hassan ShabbirPosted Apr 6, 2022, 11:29 AM
Hi Khushbu, Iam trying this with .net core 6 but here var IsAuthenticated = context.HttpContext.User.Identity.IsAuthenticated; i am getting alwasy false., in program file i am setting bearer token but here isauthenticated always false ..
Mansoor AhmedPosted Feb 13, 2022, 10:46 AM
Hi Khushbu, Could You Please Explain This In Web Forms Too. If It Is Possible Please.
Hamid KhanPosted Jan 9, 2022, 4:20 PM
Nice explanation
Byron ByronPosted Jan 3, 2022, 1:06 AM
Thanks Khushbu Saini for this tutorial, I would like to ask you if this code is in github?
Tousif TahirPosted May 4, 2021, 10:33 AM
Can your share your complete project
venkatesh dharavathPosted Apr 7, 2021, 5:07 PM
Nice one. I have a doubt, We have created async CreateAuthenticationTicket in which we're not awaiting for anything.
ehrojasPosted Dec 2, 2020, 2:23 PM
Can you please provide the source code.
미진 김Posted Nov 15, 2020, 7:56 PM
Where is AdminLogin class ?
Miguel ArevaloPosted Nov 10, 2020, 11:58 PM
Great article to understand how to integrate JWT in .net! Congratulations. I have a question regarding the logout. Does it invalidates the current JWT? I mean, if someone else steal the JWT can it use it after the user hits logout?
Joyab KhanPosted Nov 2, 2020, 4:08 AM
This is really very helpful for me...
Imran JalaliPosted Oct 27, 2020, 5:31 AM
Can you please share the code?
Dheeraj JainPosted Oct 11, 2020, 10:47 PM
You explained every thing about login authorization very helpful..
Fy thenPosted Oct 7, 2020, 11:44 PM
This is great article nice explained.
lsj lsjPosted Sep 25, 2020, 8:04 AM
Very informative one, keep going
Manish GuptaPosted Sep 12, 2020, 9:16 AM
Hi,Can you please share the code
Hamid KhanPosted Sep 11, 2020, 8:28 AM
Very Good explain.... Keep posting.........