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. :)