Contents
Part 1 covered how to Authenticate users with their login credentials. In Part 2, we are going see how to implement Authorization for users. In other words, grant permission for users to use certain part of the application or all of it. User Permission (Authorization) is handled in 3 levels, Controller, Action method and View page. For this, we will be writing custom attributes and few extension methods. Part 2 includes separate LoginDemo.sln project implemented with all the topics covered below for Authorization.
Let’s have three different roles:
Director
Supervisor
Analyst
Create a static
class Roles.cs to define user roles. These are parameter values which would be passed into custom attribute.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace LoginDemo.CustomAttributes
{
public static class Roles
{
public const string DIRECTOR = "DIRECTOR";
public const string SUPERVISOR = "SUPERVISOR";
public const string ANALYST = "ANALYST";
}
}
Let’s add “WRITE” permission to User collection.
private List UserList = new List
{
new User { USERID = "jsmith@email.com", PASSWORD = "test",
EMAILID = "jsmith@email.com", FIRST_NAME = "John",
LAST_NAME = "Smith", PHONE = "356-735-2748",
ACCESS_LEVEL = Roles.DIRECTOR.ToString(), WRITE_ACCESS = "WRITE_ACCESS" },
new User { USERID = "srob@email.com", PASSWORD = "test",
FIRST_NAME = "Steve", LAST_NAME = "Rob",
EMAILID = "srob@email.com", PHONE = "567-479-8537",
ACCESS_LEVEL = Roles.SUPERVISOR.ToString(), WRITE_ACCESS = "WRITE_ACCESS" },
new User { USERID = "dwill@email.com", PASSWORD = "test",
FIRST_NAME = "DJ", LAST_NAME = "Will",
EMAILID = "dwill@email.com", PHONE = "599-306-6010",
ACCESS_LEVEL = Roles.ANALYST.ToString(), WRITE_ACCESS = "WRITE_ACCESS" },
new User { USERID = "JBlack@email.com", PASSWORD = "test",
FIRST_NAME = "Joe", LAST_NAME = "Black",
EMAILID = "JBlack@email.com", PHONE = "764-460-8610",
ACCESS_LEVEL = Roles.ANALYST.ToString(), WRITE_ACCESS = "" }
};
User permissions are handled using attributes which can be used to decorate controller and action methods. When an attribute is decorated at top of the controller, then it applies to all the action methods in that controller. Likewise, each action method can also be decorated.
To create a customized attribute for authorization, we will be using IAuthorizationFilter
interface and TypeFilterAttribute
. IAuthorizationFilter
implements the actual filter for our authorization using OnAuthorization
method. TypeFilterAttribute
is used for dependency injection. For more information, please refer to Microsoft docs.
Let’s write custom attribute for authorization:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace LoginDemo.CustomAttributes
{
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(item, item))
flagClaim = true;
}
if (!flagClaim)
context.Result = new RedirectResult("~/Dashboard/NoPermission");
}
else
{
context.Result = new RedirectResult("~/Home/Index");
}
return;
}
}
}
As you can see, there are two classes, AuthorizeAttribute
and AuthorizeFilter
in the above code.
AuthorizeAttribute
public class AuthorizeAttribute : TypeFilterAttribute
{
public AuthorizeAttribute(params string[] claim) : base(typeof(AuthorizeFilter))
{
Arguments = new object[] { claim };
}
}
This class implements TypeFilterAttribute
which is used by dependency container to create object of AuthorizeFilter
. AuthorizeAttribute
constructor takes array of string
as parameter. Since it is an array, we can pass roles with comma (,) separated values [E.g.: “Director
”, “Supervisor
”, “Analyst
”].
AuthorizeFilter
public class AuthorizeFilter : IAuthorizationFilter
AuthorizeFilter
class implements IAuthroizationFilter
interface with OnAuthorization
method.
public AuthorizeFilter(params string[] claim)
{
_claim = claim;
}
AuthorizeFilter
constructor takes array of string
s as parameter, which is passed from AuthorizeAttribute
.
public void OnAuthorization(AuthorizationFilterContext context)
OnAuthorization
method comes with AuthorizationFilterContext
. From this “context”, we can get the HttpContext
and User Identity which carries the claims.
var IsAuthenticated = context.HttpContext.User.Identity.IsAuthenticated;
var claimsIndentity = context.HttpContext.User.Identity as ClaimsIdentity;
From the “context
” object, we get to know if the user is authenticated or not. With same “context
” object, we get the user claims identity collection.
if (IsAuthenticated)
{
bool flagClaim = false;
foreach (var item in _claim)
{
if (context.HttpContext.User.HasClaim(item, item))
flagClaim = true;
}
if (!flagClaim)
context.Result = new RedirectResult("~/Dashboard/NoPermission");
}
else
{
context.Result = new RedirectResult("~/Home/Index");
}
return;
In this block, we check if user is authenticated or not. If not, we redirect the user to Login page. Then we loop through ‘claim’ array collection (This array collection would be user roles which we would be passing as parameter from controller, e.g.: Authorize[new string[] “Director”, “Supervisor”]
).
Here, context.HttpContext.User.Identity
object carries user permissions in claims object collection. In Part 1, we created token with user claims and loaded into context.HttpContext.User
identity object. Please refer to Part 1 under “Middleware app.UseAuthentication()
”.
Inside the loop, we check if the parameter value(s) is in the user identity claims collection using “HasClaim
” method. In Part 1, it's explained how User Claims Identity object collection is created and assigned to HttpContext
. It’s the same HttpContext
from which we are getting the User Claims and checking against the parameter value(s) passed.
If the parameter value is found in the claims collection, then the user is authorized and let pass through the Http Request. If not, we redirect the user to a page which says, you do not have permission. In this article, it's redirected to “No Permission” page.
Now that we have created a custom attribute to authorize, it’s time to use it in the controller.
public class DashboardController : Controller
{
[Authorize(Roles.DIRECTOR)]
public IActionResult DirectorPage()
{
return View("DirectorPage");
}
[Authorize(Roles.SUPERVISOR)]
public IActionResult SupervisorPage()
{
ViewBag.Message = "Permission controlled through action Attribute";
return View("SupervisorPage");
}
[Authorize(Roles.ANALYST)]
public IActionResult AnalystPage()
{
return View("AnalystPage");
}
}
Action methods are decorated with [Authorize]
attribute. We are passing user roles as parameters. Director
, Supervisor
and Analyst
each have separate action method.
[Authorize(Roles.DIRECTOR)]
public IActionResult DirectorPage()
{
return View("DirectorPage");
}
In this ‘DirectorPage
’ action method, we have set the Authorize
attribute with Roles.DIRECTOR
. Which means, only users with Director
role can view the page. If Supervisor
or Analyst
try to access the page, then they will be redirected to “No Permission
” page from the AuthorizeFilter
class.
Roles.DIRECTOR
is the parameter which we are passing to AuthorizeFilter
class. Authorize
filter class takes the “Roles.DIRECTOR
” parameter value and checks if the value is found in User Claims Identity collection. If it’s found, then the user is allowed to pass through the action method and the user is allowed to see “DirectorPage
”. If the logged in user is a Supervisor or Analyst, then they cannot see the ‘DirectorPage
’.
If we want to allow multiple users to have access to action method, then we can pass the parameter values with comma(,) separated values like below:
[Authorize(Roles.DIRECTOR, Roles.SUPERVISOR, Roles.ANALYST)]
public IActionResult AllRoles()
{
return View();
}
To set permission on controller level, we can set it like below. When Authorize
attribute is set on controller level, then the permission is set for all action methods in that controller.
namespace LoginDemo.Controllers
{
[Authorize(Roles.DIRECTOR, Roles.SUPERVISOR, Roles.ANALYST)]
public class YourController : Controller
{
public IActionResult Action1()
{
return View();
}
public IActionResult Action2()
{
return View();
}
public IActionResult Action3()
{
return View();
}
}
}
Filter attributes can only be used in controller. But there are places where we need to check user permission and we can’t rely only on filter attributes. What if we want to check user roles inside action method in an “If
” condition? What if we want to check user roles in View Page? In this case, we can’t use filter attributes. For this reason, we are going to have extension methods. One for controller action method and one for View Page.
Let’s create a static
class PermissionExtension.cs to have extension method for controller.
namespace LoginDemo.CustomAttributes
{
public static class PermissionExtension
{
public static bool HavePermission(this Controller c, string claimValue)
{
var user = c.HttpContext.User as ClaimsPrincipal;
bool havePer = user.HasClaim(claimValue, claimValue);
return havePer;
}
public static bool HavePermission(this IIdentity claims, string claimValue)
{
var userClaims = claims as ClaimsIdentity;
bool havePer = userClaims.HasClaim(claimValue, claimValue);
return havePer;
}
}
}
Extension method is implemented for use in controller and in view page. These methods take claims value as parameter and checks if that claim exists in the HttpContext.User
claims object collection. To invoke the method in controller, we are using “this Controller” as first parameter which makes it an extension method. For use in view page, it's “this IIdentity
”.
These extension methods are for convenience and to keep things in one place. You can also directly use “User.HasClaims()
” in your action method and in view page.
Say suppose you have an action method and want to use it for more than one role. But you want to do different logic or get data from different source or something specific based on role. In this case, we need to know the logged in user role inside the action method.
In the below action method, all logged in users have permission. We check user roles inside action
method. Inside the action
method, I want to return a different view based on role. For “Supervisor
”, it returns “SupervisorPage
” view, for “Analyst
” it returns “AnalystPage
” view. This is only for example, it can be used to implement different logic, get data from different source, etc.
It’s a simple if
condition with extension method HavePermission()
which controls the permission.
public IActionResult SupervisorAnalystPage()
{
ViewBag.Message = "Permission controlled inside action method";
if (this.HavePermission(Roles.SUPERVISOR))
return View("SupervisorPage");
if (this.HavePermission(Roles.ANALYST))
return View("AnalystPage");
return new RedirectResult("~/Dashboard/NoPermission");
}
Above, we have created HavePermission()
extension method. Using the extension method, we control the permission with simple “if
” condition. Extension method checks for user role in HttpContext
user claims object collection.
this.HavePermission(Roles.SUPERVISOR)
this.HavePermission(Roles.ANALYST))
What if we want to control something in View Page based on user role/permission? How to show and hide different top "Menu" items each for Director, Surpervisor and Analyst? For this we need to know user permission in view page level. We want somethis like, if the user is Director, then show/hide a menu, button etc,.
Let's say we want to disable and enable “Save” button based on user role/permission. This can be done with the above HavePermission()
extension method. In this example, button is disabled for user who do not have WRITE access. In this view page, there is a form which takes input from user. This form can only be saved by users who have WRITE access. For others, “Save” button is disabled and they cannot save the form data.
@if (User.Identity.HavePermission("WRITE_ACCESS") == true)
{
<button type="button"</button<>
}
else
{
<button type="button" disabled="disabled"<</button>
}
Above, we have created two HavePermission()
extension methods, one for Controller and one for View Page. Here HavePermission()
checks for “WRITE_ACCESS
” claim in HttpContext
user claims object collection. If true
, we enable save button, otherwise it's disabled. Like this, we can control “What to show?” and “How to show?” view page content for users based on their role/permission.
@if (User.Identity.HavePermission("WRITE_ACCESS") == true)
Login to demo project as Analyst JBlack@email.com who does not have WRITE permission. In the landing page, click on “See how page level permission works”.
You can see “Save” button is disabled and user cannot save the form data.
For other users, they have WRITE permission and “Save” button is enabled to save form data.
How to restrict users who are not signed-in to application, but directly tries to access a page by giving the URL of that page? Say application URL is http://www.yourapplication.com which takes users to login page, But there is a page for “Supervisor” and the user knows the URL of that page, if “Supervisor” page URL is http://www.yourapplication.com/supervisor and user directly enters the URL in browser without login, then it is an unauthorized access. Let’s see how to handle this.
We are going to implement a filter attribute (similar to AuthorizeFilter
). But this we will be using it in controller level. Create a class UnAuthorized.cs. Implement IAuthorizationFilter
interface and handle the request in OnAuthroization()
method. We don’t have to pass any parameter values for this filter. This filter only checks for Authentication.
namespace LoginDemo.CustomAttributes
{
public class UnAuthorizedAttribute : TypeFilterAttribute
{
public UnAuthorizedAttribute() : base(typeof(UnauthorizedFilter))
{
}
}
public class UnauthorizedFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
bool IsAuthenticated = context.HttpContext.User.Identity.IsAuthenticated;
if (!IsAuthenticated)
{
context.Result = new RedirectResult("~/Home/Index");
}
}
}
}
Get user identity object from AuthorizationFilterContext
, from which we can find out if the user is authenticated.
bool IsAuthenticated = context.HttpContext.User.Identity.IsAuthenticated;
If the user is not authenticated or login user, redirect the user to login page.
if (!IsAuthenticated)
{
context.Result = new RedirectResult("~/Home/Index");
}
This you can use it in controller level by simply adding the [UnAuthorized]
attribute on the top, which applies for all the action methods in that controller. Authorize
attribute also checks for IsAuthenticated
, so one can ask what is the use of [UnAuthorized]
attribute. There could be a case where permission is not controlled, which means all the user can have permission for an action method and there is no [Authorize]
attribute for that action method. In the below controller, SupervisorAnalystPage()
action method does not have [Authorize]
attribute. Any user who knows the URL can try to access this. Another reason to have [UnAuthorized]
attribute is to handle Ajax calls, which we will see in the next topic.
namespace LoginDemo.Controllers
{
[UnAuthorized]
public class DashboardController : Controller
{
[Authorize(Roles.DIRECTOR)]
public IActionResult DirectorPage()
{
return View("DirectorPage");
}
[Authorize(Roles.SUPERVISOR)]
public IActionResult SupervisorPage()
{
ViewBag.Message = "Permission controlled through action Attribute";
return View("SupervisorPage");
}
[Authorize(Roles.ANALYST)]
public IActionResult AnalystPage()
{
return View("AnalystPage");
}
public IActionResult SupervisorAnalystPage()
{
ViewBag.Message = "Permission controlled inside action method";
if (this.HavePermission(Roles.SUPERVISOR))
return View("SupervisorPage");
if (this.HavePermission(Roles.ANALYST))
return View("AnalystPage");
return new RedirectResult("~/Dashboard/NoPermission");
}
}
}
Before we implement the code, let’s see “Why?” “Where?” and “How?” to do this.
Users can leave the application idle till the session expires. When session expires, token is not available and user is logged off from application. But the page is still open in the browser. Not knowing that the session expired and user is logged off, users can click anything in the page. If that click is a regular http call (where page reload happens or something), then the user would be automatically redirected to login page. If that click happens to be an Ajax call, then the page would remain as it is and redirection to login page will not happen.
P.S.: Ajax calls are also an HTTP call. Regular HTTP call and Ajax call differ the way it is called. Mostly regular HTTP calls are directly executed by browser. Ajax calls are made from code(javascript/jquery) and then the browser executes the call. For regular HTTP call, the return result can be View Page or Json result, etc. But with Ajax call, it's only Json result.
- Extension method to identify Ajax calls
- Handle Ajax call Authentication in
[UnAuthorized]
filter attribute - Handle Ajax call Authorization in
[Authorize]
filter attribute - Catch Http Status code for Ajax call in jquery and redirect to login page
Extension Method to Identify Ajax Calls
First, we need to know if a request is an Ajax call or a regular HTTP call. This we can find through Http Headers. Second, we are going to create an extension method so that we can use it with the Http Request object.
Create a static
class AjaxExtension.cs and a static
method “IsAjaxRequest
”. Add the below code:
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace LoginDemo.CustomAttributes
{
public static class AjaxExtension
{
public static bool IsAjaxRequest(this HttpRequest request)
{
if (request == null)
throw new ArgumentNullException("request");
if (request.Headers != null)
return request.Headers["X-Requested-With"] == "XMLHttpRequest";
return false;
}
}
}
It’s a simple extension method implemented with HttpRequest
object. We can find if a request is an Ajax call with one of the Http Headers "X-Requested-With
". If this header value is “XMLHttpRequest
”, then it's an Ajax call.
return request.Headers["X-Requested-With"] == "XMLHttpRequest";
Handle Ajax Call Authentication in [UnAuthorized] Filter Attribute
Now we have an extension method IsAjaxRequest()
to find if a request is Ajax call. Let’s add a condition to [UnAuthorized]
filter attribute using the extension method.
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 LoginDemo.CustomAttributes
{
public class UnAuthorizedAttribute : TypeFilterAttribute
{
public UnAuthorizedAttribute() : base(typeof(UnauthorizedFilter))
{
}
}
public class UnauthorizedFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
bool IsAuthenticated = context.HttpContext.User.Identity.IsAuthenticated;
if (!IsAuthenticated)
{
if (context.HttpContext.Request.IsAjaxRequest())
{
context.HttpContext.Response.StatusCode =
(int)HttpStatusCode.Forbidden;
}
else
{
context.Result = new RedirectResult("~/Home/Index");
}
}
}
}
}
As you can see the condition context.HttpContext.Request.IsAjaxRequest()
which checks if it’s an Ajax call. If it’s an Ajax call, we do not redirect the call. Redirection will not work with Ajax calls. Return result for Ajax call can only be a data. Here, we set the Http Response Status Code to 403 – Forbidden. This says Ajax call ended up in Error and the call was unsuccessful. All the Ajax calls in this demo are written in jquery. Jquery Ajax calls can get back Http Status code from HTTP Response object(header). If it’s a regular Http call, then redirect to Login page. We are done with authenticating Ajax request. Next, we need to redirect the user to login page.
Handle Ajax Call Authorization in [Authorize] Filter Attribute
For Authentication, we set the Http Status code as 403 Forbidden. For Authorization, we are going to set the Http Status Code as 401 Unauthorized. It’s the same logic where we check if it’s an Ajax call using extension method IsAjaxRequest()
. If it’s an Ajax call, set Http Status Code as 401 Unauthorized. If it’s a regular Http call, then redirect to “No Permission” page.
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 LoginDemo.CustomAttributes
{
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(item, item))
flagClaim = true;
}
if (!flagClaim)
{
if (context.HttpContext.Request.IsAjaxRequest())
context.HttpContext.Response.StatusCode =
(int)HttpStatusCode.Unauthorized;
else
context.Result =
new RedirectResult("~/Dashboard/NoPermission");
}
}
else
{
if (context.HttpContext.Request.IsAjaxRequest())
{
context.HttpContext.Response.StatusCode =
(int)HttpStatusCode.Forbidden;
}
else
{
context.Result = new RedirectResult("~/Home/Index");
}
}
return;
}
}
}
Catch Http Status Code for Ajax Call in Jquery and Redirect to Login Page
Here, we are going to get back the HTTP Status Code set in [UnAuthorized]
filter attribute. It should be done from the place where Ajax call is made. As said before, in this demo, we are using Jquery to make Ajax calls. Jquery comes with a method .ajaxError
to catch errors happened during Ajax call. But are we going to write .ajaxError
method for each and every Ajax call? No, .ajaxError
method can be implemented globally for the whole application which would handle errors for all Ajax calls. Only point, .ajaxError
method should be available in that page. All we have to do, is to add it in a common page _Layout.cshtml which is the master page. Add this script to your _Layout.cshtml or any master page you use.
<script>
$(document).ajaxError(function (xhr, result) {
if (result.status === 403) {
window.location.href = '/Home/Index';
}
if (result.status === 401) {
window.location.href = '/Dashboard/NoPermission';
}
});
</script>
.ajaxError
gets the Http headers in one of the parameters, here, it's declared as “result
”. Http header and status code 403 Forbidden set in [UnAuthorized]
filter attribute is returned in “result
” parameter. If the result.status
is 403, then we redirect the user to login page from client side.
if (result.status === 403) {
window.location.href = '/Home/Index';
}
In the demo project, there is a page CheckAjaxCalls.cshtml where you can check authentication/authorization for Ajax call. To check for authentication, Login to demo project as a Director jsmith@email.com. You should see the below page.
Click on the link “See how Authentication & Authorization handled for Ajax Calls”. In this page, you can check both authentication and authorization.
The above screen has 3 buttons, “End Session”, “Authenticate Ajax Call” and “Authorize Ajax Call”. All 3 have JavaScript function (OnClick_EndSession
, OnClick_AuthenticateAjaxCall
, OnClick_AuthorizeAjaxCall
) which makes the Ajax call. Below is the complete code with HTML tags.
<script>
function OnClick_EndSession() {
$.ajax({
type: 'GET',
url: '/Home/EndSession',
data: {},
cache: false,
success: function (result) { }
});
alert("End of User Session,
Click on Ajax Call button to autneticate Ajax calls,
It should take you to login page.");
}
function OnClick_AuthenticateAjaxCall() {
$.ajax({
type: 'GET',
url: '/Dashboard/AuthenticateAjaxCalls',
data: {},
cache: false,
success: function (result) {
if (result != "")
alert("Your session is still active,
end session to see how authentication for Ajax call works!");
}
});
}
function OnClick_AuthorizeAjaxCall() {
$.ajax({
type: 'GET',
url: '/Dashboard/AuthorizeAjaxCalls',
data: {},
cache: false,
success: function (result) {
if (result != "")
alert("Your have permission for this Ajax call!");
}
});
}
</script>
Below is the Controller action method for the 3 Ajax calls for the 3 buttons in the page which returns Json result. This code is in demo project DashboardController.cs file. You can see “AuthorizeAjaxCalls
” action method has [Authorize]
attribute set for Director
and Supervisor
.
public JsonResult AuthenticateAjaxCalls()
{
return Json(new {result = "success" });
}
[Authorize(Roles.DIRECTOR, Roles.SUPERVISOR)]
public JsonResult AuthorizeAjaxCalls()
{
return Json(new { result = "success" });
}
public JsonResult EndSession()
{
HttpContext.Session.Clear();
return Json(new {result = "success"});
}
Now click on “Authenticate Ajax Call” button. If the session is still active, you should get an alert message.
To end session, click on “End Session”, then click on “Authenticate Ajax Call”. You should be redirected to login page.
To check Authorization, login to demo project as JBlack@email.com who is in Analyst Role. In this demo, Ajax call is only for Director and Supervisor. Analysts do not have permission for the Ajax call, so they will be redirect to “No Permission” page. After login, click the link “See how Authentication & Authorization handled for Ajax Calls”. In next page, click “Authorize Ajax Call”. Since JBlack@email.com is an Analyst, he does not have permission and will be redirected to “No Permission” page.
If you log in as a Director or Supervisor, then you would see an alert message when you click on “Authorize Ajax Call”.
Fully working LoginDemo.sln project is available for download. See the below screen shots for quick glimpse of the LoginDemo.sln project.
Login Page
Landing Page
Top banner shows signed in user name and his role for all the pages. Click on the given links to check different scenarios.
In Part 3, we will cover how to do Forgot and Reset password.
ASP.NET CORE Token Authentication and Authorization using JWT (No Cookies) – Part 1