0

A lot of my methods in my WebAPI looks like this. I have an authorization-filter on policy, but then i also need to validate my token and that the user provided in the token exists in DB. I am wondering if there is a way of extending the Authorize attribute so that after policy is validated, the token gets validated too. And is it also possible to return the user into the method or context if existing?

[Authorize(Policy = "Admin")]
[Route("get")]
[HttpGet]
public async Task<IActionResult> Get()
{
    var (success, user) = await UserHelpers.ValidateTokenAndGetUserAsync(HttpContext, _userManager, _configuration, _logger, ControllerContext, ModelState);
    if (!success || user?.CustomerId == null) return Unauthorized(HttpResponseHelper.GetErrorResponse(StatusCodes.Status401Unauthorized, _localizer[ResourceConstants.Unauthorized.UserNotFoundError].Value));
        
    //Code
        
    await UserHelpers.CookieToResponse(user, _configuration, _webHostEnvironment, Response, Request).ConfigureAwait(false);

    return Ok();
}
OJs
  • 107
  • 1
  • 11

1 Answers1

1

First, I should address that you shouldn't customize Authorize attribute.

Using (Policy, Claim, Requirement) can help you to customize your authorization based on your business.

Then my question is that your user was in the database while issuing the token. So how can it be removed now? (The user in the JWT-Token is being validated via the signature of that)

If you want to double-check if the user is enabled, or not archived yet you can write another filter like this:

public class ApiController : Controller
{
    [Authorize(Policy = "Bla")]
    [CheckUserIsEnabled]
    public async Task<IActionResult> Get()
    {
        return Ok();
    }
}

public class CheckUserIsEnabledAttribute : Attribute, IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var userId = context.HttpContext.User.FindFirst(x => x.Type == System.Security.Claims.ClaimTypes.NameIdentifier);

        if (userId is null)
        {
            context.Result = new UnauthorizedResult();
            return;
        }

        bool exists = true;
        //exists = db.CheckIfUserExistsAsync(userId);

        if (!exists)
        {
            context.Result = new UnauthorizedResult();
            return;
        }

        await next();
    }
}

This solution works because the JWT claims will be added to current user claims on httpRequest instantiation (even if you don't put Authorize attribute on the corresponding action)

Amir
  • 1,214
  • 7
  • 10