Question

The admin section of a MVC3 website is created as an Area. I then put the following code in the Web.config

<location path="Admin">
<system.web>
  <authentication mode="Forms">
    <forms loginUrl="~/Admin/Login/Login" timeout="5000" defaultUrl="~/Admin/Login/Redirect" />
  </authentication>
  <authorization>
    <deny users="?"/>
  </authorization>
</system.web>
</location>

However it throws an error

Parser Error Message: It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.

Source Error:

Line 44:   <location path="Admin">
Line 45:     <system.web>
Line 46:       <authentication mode="Forms">
Line 47:         <forms loginUrl="~/Admin/Login/Login" timeout="5000" defaultUrl="~/Admin/Login/Redirect" />
Line 48:       </authentication>
Was it helpful?

Solution

You cannot override the <authentication> node for particular subfolders. This simply is not supported. If you want to have a different login page for your area you could write a custom [Authorize] attribute and then decorate all your controller actions in the Area with it. The idea is to override only the HandleUnauthorizedRequest method and redirect to the desired login page.

For example:

public class AdminAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        var routeValues = new RouteValueDictionary(new
        {
            controller = "login",
            action = "login",
            area = "admin"
        });
        filterContext.Result = new RedirectToRouteResult(routeValues);
    }
}

And as far as your web.config is concerned, the <authentication> node must be configured directly under the <system.web> section and not inside a <location> section.

OTHER TIPS

I have tried to explain

if your application contain, multiple area, when application run, all area gets registered. so that login user can access every area.

But if you want to allow access only particular area, then you need to override default area registration process.

In that process, we removed, all routes belongs to each Area

while(RouteTable.Routes.Count > 0) RouteTable.Routes.RemoveAt(0);

After that, we allow only those Areas which we want to allow to login user, for that we used

MvcApplication app = (MvcApplication)HttpContext.ApplicationInstance;
RouteCollection existingcoll = outeCollection)app.Application["ExistingRoutecolling"];

foreach (Route _route in existingcoll)
 {
    // allow only those routes , which belongs to the area which you want allow to access the login user
    if (_route.Url == "Admin/{controller}/{action}/{id}")
        RouteTable.Routes.Add((RouteBase)_route);       
    // re-register routes again
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    // now redirect with expected action
    return RedirectToAction("controller", "action", new { area = "Admin" });
}
public class MvcApplication : System.Web.HttpApplication
 {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            RouteCollection existingcoll = new RouteCollection();

            foreach (Route _route in RouteTable.Routes)
                existingcoll.Add((RouteBase)_route);
            //keep all default registerd routes in Asp Application object  
            Application["ExistingRoutecolling"] = existingcoll;
        }
}
//after login when user called first action to render dashboard, you can add logic there
 public ActionResult ModuleDashboard
 {
     //get default registerd routes from Asp Application object which we stored in  Application_Start() method 
    MvcApplication app = (MvcApplication)HttpContext.ApplicationInstance;
    RouteCollection existingcoll = (RouteCollection)app.Application["ExistingRoutecolling"];

    // remove all register routes, by default those are registered by application object
    while (RouteTable.Routes.Count > 0)
        RouteTable.Routes.RemoveAt(0);

    //navigate each route from collection and add in actual application route collection object         
     foreach (Route _route in existingcoll)
     {
        // allow only those routes , which belongs to the area which you want allow to access the login user
        if (_route.Url == "Admin/{controller}/{action}/{id}")
            RouteTable.Routes.Add((RouteBase)_route);       
        // re-register routes again
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        // now redirect with expected action
        return RedirectToAction("controller", "action", new { area = "Admin" });
    }

 }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top