Zulander
Zulander

Reputation: 824

aspcore multiple policy with JWT

I have two policy in place the ApiUser and CompanyBased. when I am using the companybased policy ([Authorize(Policy = "CompanyBased")] ) the application is failing to validate the JWT token. When I am using [Authorize] it works well, the token is validated...

Version: core 2.2

Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Authorization failed. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. Microsoft.AspNetCore.Mvc.ForbidResult[1] Executing ForbidResult with authentication schemes (). Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[13] AuthenticationScheme: Bearer was forbidden.

        // api user claim policy
        services.AddAuthorization(options =>
        {
            options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
            options.AddPolicy("CompanyBased", policy =>
            {
                policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess);
                policy.AddRequirements(new CompanyBasedRequirement());
            });
        });

This is the CompanyBasedHandler

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CompanyBasedRequirement requirement)
{
    #region Validate Company id

    Guid? companyId = _httpContextAccessor.HttpContext.Request.Headers.GetCompanyId();
    string nameIdentifier = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (companyId is null)
    {
        _logger.LogInformation($"No company suppied for {nameIdentifier}");
        context.Fail();
    }
    else
    {
        if (!_clientRepository.IsClientValid(companyId.Value, nameIdentifier))
        {
            _logger.LogInformation($"{companyId} does not belong to {nameIdentifier}");
            context.Fail();
        }
        else
        {
            context.Succeed(requirement);
        }
    }

    #endregion Validate Company id

    return Task.CompletedTask;
}
  1. How do I make sure that CompanyBased validates the the JWT token
  2. Can I make the HandleRequirementAsync Async with await, I was stuck with return await Task.CompletedTask (which is not working)!

Upvotes: 0

Views: 870

Answers (2)

Zulander
Zulander

Reputation: 824

I was missing the Constants.Strings.JwtClaimIdentifiers.Rol in the token!

Upvotes: 0

user1336
user1336

Reputation: 7205

Make sure that you regisered your custom authorization handler correctly in your dependency injection container in the Startup class. It should be registered as a singleton:

services.AddSingleton<IAuthorizationHandler, CompanyBasedHandler>();

You can make the HandleRequirementAsync async/await by changing the the method signature to async Task and then not returning a completed Task at the end of the method, for example:

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, CompanyBasedRequirement requirement)
{
    #region Validate Company id

    Guid? companyId = _httpContextAccessor.HttpContext.Request.Headers.GetCompanyId();
    string nameIdentifier = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (companyId is null)
    {
        _logger.LogInformation($"No company suppied for {nameIdentifier}");
        context.Fail();
    }
    else
    {
        if (!_clientRepository.IsClientValid(companyId.Value, nameIdentifier))
        {
            _logger.LogInformation($"{companyId} does not belong to {nameIdentifier}");
            context.Fail();
        }
        else
        {
            context.Succeed(requirement);
        }
    }

    #endregion Validate Company id
}

Note that you are not doing any asynchronous operations in the method, that means it will run synchronously thus there is not need to make this method async.

Upvotes: 1

Related Questions