How can we set authorization for a whole area in ASP.NET MVC?
If all of your admin code is in one controller then add Authorize to the entire class.
[Authorize]
public class AdminController : Controller
{
.......
}
I just started on this... but so far this is working pretty good for me.
I create a custom AuthorizeAttribute class and add this in the RegisterGlobalFilters function.
In CustomAuthorizeAttribute I check for various conditions based on the area it is in.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomAuthorizeAttribute());
filters.Add(new HandleErrorAttribute());
}
}
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var routeData = httpContext.Request.RequestContext.RouteData;
var controller = routeData.GetRequiredString("controller");
var action = routeData.GetRequiredString("action");
var area = routeData.DataTokens["area"];
var user = httpContext.User;
if (area != null && area.ToString() == "Customer")
{
if (!user.Identity.IsAuthenticated)
return false;
}
else if (area != null && area.ToString() == "Admin")
{
if (!user.Identity.IsAuthenticated)
return false;
if (!user.IsInRole("Admin"))
return false;
}
return true;
}
}
Web.config-based security should almost never be used in an MVC application. The reason for this is that multiple URLs can potentially hit a controller, and putting these checks in Web.config invariably misses something. Remember - controllers are not associated with areas, routes are associated with areas. The MVC controller factory will happily serve controllers from the Areas/ folder for non-area requests if there's no conflict.
For example, using the default project structure, adding an Admin area with an AdminDefaultController, you can hit this controller via /Admin/AdminDefault/Index and /AdminDefault/Index.
The only supported solution is to put your attribute on a controller base class and to ensure that each controller within the area subclasses that base class.
I have just been investigating this same issue. Since it is not possible to secure controllers based on areas, a simpler option comes to mind.
Create a base controller definition for each area that overrides Controller, and add the security require to this. Then you just have to ensure each controller in the area overrides AreaController instead of Controller. For example:
/// <summary>
/// Base controller for all Admin area
/// </summary>
[Authorize(Roles = "Admin")]
public abstract class AdminController : Controller { }
It does still require that you derive each controller in the Admin area from this base,
public class HomeController : AdminController
{
// .. actions
}
but at least you have a single point where you define the security for the area.