Custom AuthorizeAttribute with custom authentication

JustAMartin picture JustAMartin · Oct 1, 2012 · Viewed 16.4k times · Source

I am using ASP.NET MVC 4 Web application as a front-end for some WCF services. All the user log in/log out and session control is done on the back-end. MVC app should only store a single cookie with session ID. My client does not allow to use Forms Authentication, everything must be customized.

I have set up the following in my web.config:

  <system.web>
...
    <authentication mode="None" />
  </system.web>

  <system.webServer>
    <modules>
...
      <remove name="FormsAuthentication" />
...    
    </modules>
  </system.webServer>

I have also a global filter:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        // Force all actions to request auth. Only actions marked with [AllowAnonymous] will be allowed.
        filters.Add(new MyAuthorizeAttribute());
    }
}

which is called in Global.asax

   FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

I have marked with [AllowAnonymous] every controller and action which does not need authorization.

And now I have to implement MyAuthorizeAttribute. I have tried some tutorials, but none of them completely match my scenarios.

Basically, I have to handle the following scenarios for each action:

  1. If there is a valid cookie, the current request should be considered authorized (there will be no any roles to check, only one kind of users).
  2. If there is no cookie, I should override the default MVC handler (which tries to load Account/Login) and redirect users to Home/Index page with a message that the user should log in.
  3. If the WCF method call throws FaultException where our custom SecurityFault says that session has expired (SecurityFault has a custom enum field which contains the reason of exception), I should destroy my custom session cookie and again redirect the user to Home/Index page with a message that the user should log in because his last session has expired. For all the other SecurityFaults I can let them go through - I have a global error handler.

As far as I understand, I need to override AuthorizeCore (to check my cookie to see if the session exists and is still valid) and HandleUnauthorizedRequest (to redirect users to Home/Index instead of default Login page).

For redirection I tried:

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {            
        base.HandleUnauthorizedRequest(filterContext);
        filterContext.Result = new RedirectResult("/Home/Index/NeedsLogin");
    }

which seems to handle the scenario 2nd fine (I'm not sure about that base call, though - is it needed?).

For the 1st scenario, I need to implement AuthorizeCore. I'm not sure, how to do it correctly. I have seen that AuthorizeAttribute has some code for handling caching situations and maybe many more hidden functionality and I don't want to break it.

For the 3rd scenario, I am not sure if MyAuthorizeAttribute will be able to handle it. Can AuthorizeAttribute catch exceptions which occur inside of the Action or I'll have to handle SecurityFault.SessionExpired situations in my global error handler?

Answer

Jive Boogie picture Jive Boogie · Oct 1, 2012

Not totally sure I get it but if you create an Custom Authorization Filter that inherits from System.Web.MVC.Authorize attribute like this.

    public class CustomAuthorize : AuthorizeAttribute
    {
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (CookieIsValid(filterContext.Request.Cookies["cookieyouwant"])
        {
             filterContext.Result = new RedirectResult("DestUrl");
        }
        else
        {
            filterContext.Result = new RedirectResult("/Home/Index/NeedsLogin");
        }
    }
}

And then decorate your Methods that need to employ this Authorization will that do the trick?