Search code examples
c#asp.net-coreasp.net-core-identity

ASP.NET Core 2.0 How to access UserManager in a policy?


I have this requirement class that needs access to usermanager

public class NoAdminRequirment : IAuthorizationRequirement
{
    bool NoAdmins { get; set; }
    private readonly UserManager<IdentityUser> userManager;

    public NoAdminRequirment(UserManager<IdentityUser> userManager)
    {
        this.userManager = userManager;
            NoAdmins = userManager.GetUsersInRoleAsync("administrators").Result.Count() == 0;
    }
}

My understanding is that the usermanager is being initialized automatically by dependency injection since I have that set up in my application

Well this is not very usefull since I need to pass the usermanager in the policy now

services.AddAuthorization(option =>
{
    option.AddPolicy("NoAdmins", policy => policy.Requirements.Add(new { /*???*/ }));
});

Can someone suggest an alternative or a way to access the usermanager?


Solution

  • I think this should do the trick:

    public class ExcludeRoleRequirement : IAuthorizationRequirement
    {
      public string Role { get; private set; }
    
      public ExcludeRoleRequirement(string role)
      {
        Role = role;
      }
    }
    

    Since ExcludeRoleHandler is registered to the DI container, and i'm assuming that the UserManager is registered too, you can add UserManager to the constructor

    public class ExcludeRoleHandler : AuthorizationHandler<ExcludeRoleRequirement>
    {
      private readonly UserManager<IdentityUser> _manager;
      public ExcludeRoleHandler(UserManager<IdentityUser> manager)
      {
        _manager = manager;
      }
      protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, 
        ExcludeRoleRequirement requirement)
      {
        var usersInRole = await _manager.GetUsersInRoleAsync(requirement.Role);
        if (!usersInRole.Any())
        {
          context.Succeed(requirement);
        }
    
        return Task.CompletedTask;
      }
    }
    

    Then in Startup.cs:

    services.AddAuthorization(option => {
      options.AddPolicy("NoAdmin", policy =>
        policy.Requirements.Add(new ExcludeRoleRequirement("administrators")));  
    });
    
    
    services.AddSingleton<IAuthorizationHandler, ExcludeRoleHandler>();
    

    Hope this helps

    EDIT: I forgot to add

    [Authorize(Policy = "NoAdmin")]
    public class NotForAdminController : ControllerBase
    {
    }