Reputation: 12011
I would like to implement the following in MVC6:
[Authorize(Roles = "Shopper")]
public class HomeController
{
[Authorize(Roles = "Editor"), OverrideAuthorization]
public IActionResult EditPage() {}
}
But OverrideAuthorizationAttribute no longer exists. So how do you set it so that a user only needs to be in the Editor
role and not Editor
and Shopper
role to access EditPage in MVC6?
Upvotes: 4
Views: 1684
Reputation: 34992
I found this blog post from Filip W that explains how write your own solution using the filter providers.
However the framework has changed a lot and his solution has to be updated to take into account the changes in the framework up to beta8.
First you will create a new attribute where you can specify the type of the filter that you want to override. (In your case this would be the AuthorizeFilter
)
public class OverrideFilter : ActionFilterAttribute
{
public Type Type { get; set; }
}
If you want. you could create more specific filters like:
public class OverrideAuthorization : OverrideFilter
{
public OverrideAuthorization()
{
this.Type = typeof(AuthorizeFilter);
}
}
Then you need to create a new IFilterProvider
.
FilterProviderContext.Results
and search for your OverrideFilter
For example create a new OverrideFriendlyFilterProvider
following this idea:
public class OverrideFriendlyFilterProvider : IFilterProvider
{
//all framework providers have negative orders, so ours will come later
public int Order => 1;
public void OnProvidersExecuting(FilterProviderContext context)
{
if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
{
//Does the action have any OverrideFilter?
var overrideFilters = context.Results.Where(filterItem => filterItem.Filter is OverrideFilter).ToArray();
foreach (var overrideFilter in overrideFilters)
{
context.Results.RemoveAll(filterItem =>
//Remove any filter for the type indicated in the OverrideFilter attribute
filterItem.Descriptor.Filter.GetType() == ((OverrideFilter)overrideFilter.Filter).Type &&
//Remove filters with lower scope (ie controller) than the override filter (i.e. action method)
filterItem.Descriptor.Scope < overrideFilter.Descriptor.Scope);
}
}
}
public void OnProvidersExecuted(FilterProviderContext context)
{
}
}
You need to register it on the ConfigureServices
of your startup class:
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IFilterProvider, OverrideFriendlyFilterProvider>());
With all this pieces you will be able to override the authorization filter (or any other filter).
For example in the default HomeController of a new mvc application, any logged in user will be able to access the Home action, but only the ones with the admin role will be able to access the About action:
[Authorize]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[Authorize(Roles = "admin"), OverrideAuthorization]
public IActionResult About()
{
return View();
}
Upvotes: 2
Reputation: 36706
I think it would be better to use the new policy based authorization approach instead of using roles directly.
There is not a lot of documentation yet about policy based authorization but this article is a good start
Upvotes: 0