ASP.NET Core policy base Authorize with RequireUser with string array

asp.net, asp.net-core, asp.net-mvc

Solution

public class UserNamesHandler : AuthorizationHandler<UserNamesRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserNamesRequirement requirement)
    {
        var userName = context.User.Identity.Name;
        if(requirement.UserNames.ToList().Contains(userName))
            context.Succeed(requirement);
        return Task.CompletedTask; // if it does not compile use Task.FromResult(0);
    }
}

public class UserNamesRequirement : IAuthorizationRequirement
{
    public UserNamesRequirement(params string[] userNames)
    {
        UserNames = userNames;
    }

    public string[] UserNames { get; set; }
}

in startup.cs add the following

public void ConfigureServices(IServiceCollection services)
{
            services.AddAuthorization(options =>
            {
                options.AddPolicy("UserNamesPolicy",
                                  policy => policy.Requirements.Add(new UserNamesRequirement("ggg","dsds")));
            });
           services.AddSingleton<IAuthorizationHandler, UserNamesHandler>()

}

Problem

I am creating policy base authorization and would like to allow multiple users in one policy to access webpage. I created policy like shown below in start up file. Question, How can I use multiple usernames in one policy? I looked at the method for`.RequireUserName`, it is only accepting string username. Policy name `AdminServiceAccount` is mostly I am interested in to add multiple users. If I use param `.RequireUserName("DOMAIN\\USER1,DOMAIN\\USER2")` will it work? I don't think so, but wanted to check if there is an alternative way. ``` services.AddAuthorization( option => { option.AddPolicy("Admin", policy => policy.RequireRole("Domain\\GroupName")); option.AddPolicy("SuperAdminUser", policy => policy.RequireUserName("DOMAIN\\SuperAdminUser")); option.AddPolicy("AdminServiceAccount", policy => policy.RequireUserName("DOMAIN\\USER1")); } ); ``` UPDATE 1: UPDATE 2: So in my Controller, I added `[Authorize(Policy = "UserNamesPolicy")]` as show below: ``` [Authorize(Policy = "UserNamesPolicy")] public class ServersController : Controller { private readonly ServerMatrixDbContext _context; public ServersController(ServerMatrixDbContext context) { _context = context; } // GET: Servers public async Task<IActionResult> Index() { // Some code here return View(); } } ``` Here is my startup file: ``` services.AddAuthorization( option => { option.AddPolicy("UserNamesPolicy", policy => policy.Requirements.Add(new UserNamesRequirement("DOMAIN\\USER1", "DOMAIN\\USER2")) ); } ); services.AddSingleton<IAuthorizationHandler, UserNamesRequirement(); ``` For `.AddSingleTon` in startup file I get below error: Here is the `handler` class: ``` public class UserNamesHandler : AuthorizationHandler<UserNamesRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserNamesRequirement requirement) { var userName = context.User.FindFirst(ClaimTypes.NameIdentifier).Value; if (requirement.Users.ToList().Contains(userName)) context.Succeed(requirement); return Task.FromResult(0); } } ``` Here is is the UserNamesRequirement class: ``` public class UserNamesRequirement : IAuthorizationRequirement { public UserNamesRequirement(params string[] UserNames) { Users = UserNames; } public string[] Users { get; set; } } ``` UPDATE 3: SOLVED!!!! Here are few changes that were added from update 2: In `UserNameshandler` class changed var userName to get values from `context.User.Identity.Name;` ``` public class UserNamesHandler : AuthorizationHandler<UserNamesRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserNamesRequirement requirement) { // var userName = context.User.FindFirst(ClaimTypes.NameIdentifier).Value; var userName = context.User.Identity.Name; if (requirement.Users.ToList().Contains(userName)) context.Succeed(requirement); return Task.FromResult(0); } } ``` In StartUp class fixed from `services.AddSingleton<IAuthorizationHandler, UserNamesRequirement>();` to `services.AddSingleton<IAuthorizationHandler,UserNamesHandler>();` Thanks to Gevory. :)

Original source