Search code examples
c#jwtasp.net-core-2.2claimsef-core-2.2

How to make a middleware that can call database to check user claims to authorize a user in asp.net core 2.2


What is the best practice to make a middleware or a proper way to implement middleware in asp.net core 2.2.

My Scenario is I have a web api build in asp.net core 2.2 and I implement authorization in my controller something like this [Authorize(Policy = "UserDelete")] UserDelete is a user claim my problem is i have many user claim can user have, more or less up to 20 claims if I save this claims in JWT it can cause large size of JWT all i want to do is to call claims or create a middleware that call the database for this claims so that all i need to save in JWT is user credentials.


Solution

  • All you need is to create an AuthorizationHandler, please follow the instructions: 1- create a class and name it MinimumPermissionHandler or whatever. copy and paste following codes in it:

    public class MinimumPermissionRequirement : IAuthorizationRequirement { }
    
    public class MinimumPermissionHandler : AuthorizationHandler<MinimumPermissionRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MinimumPermissionRequirement requirement)
        {
            if (!(context.Resource is AuthorizationFilterContext filterContext))
            {
                context.Fail();
                return Task.CompletedTask;
            }
    
            //check if token has subjectId
            var subClaim = context.User?.Claims?.FirstOrDefault(c => c.Type == "sub");
            if (subClaim == null)
            {
                context.Fail();
                return Task.CompletedTask;
            }
    
            //check if token is expired
            var exp = context.User.Claims.FirstOrDefault(c => c.Type == "exp")?.Value;
            if(exp == null || new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(long.Parse(exp)).ToLocalTime() < DateTime.Now)
            {
                context.Fail();
                return Task.CompletedTask;
            }
    
            //other checkpoints
            //your db functions to check if user has desired claims
    
            context.Succeed(requirement);
            return Task.CompletedTask;
        }
    }
    

    2- Define a policy and add the handler to services, so put this lines in your Startup class:

    public void ConfigureServices(IServiceCollection services)
    {
       //deleted extra lines for brevity 
       services.AddAuthorization(options =>
       {
          options.AddPolicy("AccessControl", policy =>
          {
               policy.RequireAuthenticatedUser();
               policy.AddRequirements(new MinimumPermissionRequirement());
          });
       });
       //injection
       services.AddScoped<IAuthorizationHandler, MinimumPermissionHandler>();
    }
    

    3- Finally for checking access permission just put this code above Controllers

    [Authorize(Policy = "AccessControl")]