Multiple Forms Login Pages

2.1k Views Asked by At

I have an MVC3 site with an admin site and a public facing site. The controllers, views, models etc for these are in the same, single MVC project. They are separated thus: the admin site resides in an MVC3 Area called Admin and the public facing site doesn't belong to an area but exists at the top level. The admin site has a Login view and the public site also has a Login view. In my web.config file I have:

<authentication mode="Forms">
  <forms loginUrl="~/Account/LogIn" timeout="2880" />
</authentication>

Now, If I access any page in the public site that requires authentication I get taken to the public site's login page, which is great. However, if I access any page in the admin Area which requires authentication then I again get taken to the public site's login page. The issue then is how do I make sure that if I am on a page in the admin Area that requires authentication that I get sent to the admin login page?

3

There are 3 best solutions below

0
On BEST ANSWER

I've faced a similar problem when needing to have a localized login page. I create a custom Authorize attribute:

public class CustomAuthorize : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        if (filterContext.Result is HttpUnauthorizedResult)
        {
            filterContext.Result = new RedirectToRouteResult(
                new System.Web.Routing.RouteValueDictionary 
                    { 
                            { "language", filterContext.RouteData.Values[ "language" ] }, 
                            { "controller", "Account" }, 
                            { "action", "LogOn" }, 
                            { "ReturnUrl", filterContext.HttpContext.Request.RawUrl } 
                    });
        }
    }
}

Just use this attribute instead of the default Authorize attribute. In your case you can check the Request url and depending on that redirect to to the appropriate login page.

0
On

You could write a custom Authorize attribute and override the HandleUnauthorizedRequest method in which you could test whether the request was made on the admin are or not and redirect accordingly.

Something along the lines of:

public class MyAuthorizeAttribute: AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        var area = filterContext.RequestContext.RouteData.Values["area"] as string;
        if (string.Equals("admin", area, StringComparison.OrdinalIgnoreCase))
        {
            // if the request was for a resource inside the admin area
            // redirect to a different login page than the one in web.config
            // in this particular case we redirect to the index action
            // of the login controller in the admin area. Adapt this
            // accordingly to your needs. You could also externalize this 
            // url in the web.config and fetch it from there if you want

            var requestUrl = filterContext.HttpContext.Request.Url;
            var urlHelper = new UrlHelper(filterContext.RequestContext);
            var url = urlHelper.Action(
                "index", 
                "login", 
                new 
                { 
                    area = "admin", 
                    returnUrl = requestUrl.ToString() 
                }
            );
            filterContext.Result = new RedirectResult(url);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

And now use this custom authorize attribute instead of the default one.

0
On

Be sure to use filterContext.RouteData.DataTokens["area"]; instead of filterContext.RouteData.Values["area"];

public class AreaAuthorizeAttribute : AuthorizeAttribute
{
    public string LoginController = "Account";
    public string LoginAction = "Login";

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        if (filterContext.Result is HttpUnauthorizedResult)
        {
            var area = filterContext.RouteData.DataTokens["area"];
            filterContext.Result = new RedirectToRouteResult(
                new System.Web.Routing.RouteValueDictionary 
                { 
                    { "area", area},
                    { "controller", LoginController }, 
                    { "action", LoginAction }, 
                    { "ReturnUrl", filterContext.HttpContext.Request.RawUrl } 
                });
        }
    }

use like this:

[AreaAuthorizeAttribute(LoginController = "AreaLoginController", Role = "Administrator")]