Search code examples
c#asp.net-core.net-corecontroller

Authorize User Before Hitting Actions


I want to authorize users before executing controller actions. In each of the actions, There are duplicated lines of code.

Is there a method so that I will able to authorize users in ControllerBase?

For example, I want to have a CustomControllerBase to put authorization logic there:

public class CustomBaseController : ControllerBase {
   // authorization logic
}

Then controllers inherit from CustomBaseController

public class FooController : CustomBaseController {
}

Here is how I authorize a user:

var userItem = dbService.GetAuthorizedUser(User) // ClaimsPrincipal
if (userItem == null) return Unauthorized(ResponseMessage.UnAuthorized);

The first 2 lines of code are run in each action.


Solution

  • I would suggest to use ASP.NET (Core) built-in security features.

    Authorize only authenticated user, unless specified differently on controller or action with global fallback policy.

    builder.Services.AddAuthorization(options =>
    {
        options.FallbackPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
    });
    

    Enable authentication and authorization middleware.

    app.UseAuthentication();
    app.UseAuthorization();
    

    Create authorization requirements with desired logic.

    public class DefaultAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement>
    {
        private IDbService _dbService;
    
        public DefaultAuthorizationHandler(IDbService dbService)
        {
            _dbService = dbService;
        }
    
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement)
        {
            // We skip as user is not authenticated. Nothing to authorize
            if (context.User == null)
            {
                return Task.CompletedTask;
            }
    
            // 
            var userItem = _dbService.GetAuthorizedUser(context.User);
    
            if (userItem != null)
            {
                context.Succeed(requirement);
            }
    
            // in some cases you want to have strict requirement
            // to force used to be denied even if other requirements are met.
            // context.Fail();
    
            return Task.CompletedTask;
        }
    }
    

    Register authorization handler to DI.

    builder.Services.AddScoped<IAuthorizationHandler, DefaultAuthorizationHandler>();
    

    Make login endpoint to allow anonymous users by overriding fallback policy.

    [AllowAnonymous]
    public class LoginController
    {
        ...
    }
    

    Related resources:

    ASP.NET Core security topics