In MVC 5 I controlled Menu Item (sitemap) visibility based on the controllers they are authorized to access.
I had a Module Management Page for assigning and un-assigning permission to each controller.
My AuthorizeAttribute looked like this:
public sealed class PermissionAttribute : AuthorizeAttribute {
public string Module { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext) {
if (!base.AuthorizeCore(httpContext)) {
return false;
}
var moduleManager = new ApplicationModuleManager();
var userId = httpContext.User.Identity.GetUserId();
return moduleManager.IsUserAccessibleModule(Convert.ToInt32(userId), Module);
}
public override void OnAuthorization(AuthorizationContext filterContext) {
base.OnAuthorization(filterContext);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
if (!filterContext.HttpContext.User.Identity.IsAuthenticated) {
base.HandleUnauthorizedRequest(filterContext);
return;
}
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "action", "AccessDenied" },
{ "controller", "Error" },
{ "area", "" }
});
}
}
And in the controller:
[Permission(Module = "Admin")]
In MVC 6, base on this question and this doc, I need to write a authorization requirements.
public class ModuleAuthorizationHandler : AuthorizationHandler<ModuleRequirement> {
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ModuleRequirement requirement) {
if (!context.User.Identity.IsAuthenticated) {
return Task.CompletedTask;
}
//Do Module check
return Task.CompletedTask;
}
}
services.AddAuthorization(options => {
options.AddPolicy("Module", policy => policy.Requirements.Add(new ModuleRequirement()));
});
[Authorize(Policy = "Module")]
How do I pass in the Module name like this: [Permission(Module = "Admin")]
for each controller? or is there a better way of doing this?
Note: I'm implementing it this way because my Roles are dynamic, it can be renamed, deleted, and new ones can be added, but Modules are static.