Monthly Archives: March 2010

Switching to Https and back to Http in ASP.NET MVC

Within ASP.Net MVC, there is a handy RequireHttpsAttribute that you can use to automatically direct an incoming action request to go through HTTPS.  Typically this would be used for a login or checkout process:

[RequireHttps]
public Actionresult LogIn()
{
...
}

Unfortunately, once switched over to HTTPS, all subsequent requests will also be sent via HTTPS as there is no build in mechanism to return the user to HTTP.

In order to resolve this, I have written a new version of the RequireHttpsAttribute that switches the user back to Http when required.

public class RequireHttpsAttribute : System.Web.Mvc.RequireHttpsAttribute
{
   public bool RequireSecure = false;
   public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
   {
       if (RequireSecure)
       {
         // default RequireHttps functionality
         base.OnAuthorization(filterContext);
       }
       else
       {
         // non secure requested
         if (filterContext.HttpContext.Request.IsSecureConnection)
         {
             HandleNonHttpRequest(filterContext);
         }
       }
    }

   protected virtual void HandleNonHttpRequest(AuthorizationContext filterContext)
   {
      if (String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
      {
         // redirect to HTTP version of page
         string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
         filterContext.Result = new RedirectResult(url);
      }
   }
}

This action filter inherits from the standard RequireHttpsAttribute and overrides the OnAuthorization method.  It also has a parameter ‘RequireSecure’ that is set when applying the filter to indicate whether it should switch to secure (HTTPS) or not.

In order to switch to HTTPS, we then use

[RequireHttps(RequireSecure = True)]
public Actionresult LogIn()
{
...
}

And then set Secure = False either on actions that require it, or at the controller level, or in my case I set it on my base controller class so that it is applied to every action that has not been specifically decorated set to be via HTTPS.

[ActionFilters.RequireHttps(RequireSecure = false)]
public abstract class ControllerBase : Controller
{
...
}