[RequireHttps(Order = 1)] public class PayController : Controller { ... }This will automatically redirect and any url:-
from: http://www.mydomain.com/pay/membership
to: https://www.mydomain.com/pay/membership
However this comes with one small glitch, after the user has finished with the pay controller and then navigates to say the home controller then the browser still shows https:// in the address bar. So is there a elegant solution to make all your other controllers http only?
One way is to create a base controller that overrides the OnAuthorization method
public class BaseController : Controller { protected override void OnAuthorization( AuthorizationContext filterContext) { //Only check if we are already on a secure connectuion and // we don't have a [RequireHttpsAttribute] defined if (Request.IsSecureConnection) { var requireHttps = filterContext.ActionDescriptor .GetCustomAttributes( typeof(RequireHttpsAttribute), false) .Count() >= 1; //If we don't need SSL and we are not on a child action if (!requireHttps && !filterContext.IsChildAction) { var uriBuilder = new UriBuilder(Request.Url) { Scheme = "http", Port = 80 }; filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri); } } base.OnAuthorization(filterContext); } }And then make all our non secure controllers inherit from this base controller:
public class CmsHomeController : BaseController { ... }Lovely!
A bit of caution here, if the user has any sort of authentication token and you revert back to non-ssl, be careful as it could easily be stolen at that point. Just an fyi for anyone else that reads this. thanks for the posting btw!
ReplyDeleteBrilliant. I have read a few other workarounds but this is the simplest and most elegant solution. Besides, it is a common practice and a good habit to inherit from a BaseController anyway.
ReplyDeleteThanks a bunch for sharing this. Rock on, Rippo.
BTW, your captcha is almost human-proof... :) It took me a few tries.
-- LK, from Florida, US.
PS: this solution does not work when [RequireHttps] attribute is declared at the Controller class level, although that is a relatively small issue to deal with.
ReplyDelete-- LK
This comment has been removed by the author.
DeleteUpdate: I have posted a modified version on overstack.com that handles the request at both Controller class and action levels and utilize any port that IIS Express assign.
ReplyDeletehttp://stackoverflow.com/questions/1639707/asp-net-mvc-requirehttps-in-production-only/12166339#12166339
(Look for Keng)
Here is the code in BaseController class
#region Override to reroute to non-SSL port if controller action does not have RequireHttps attribute to save on CPU
// Note that this code works with RequireHttps at the controller class or action level.
// Credit: Various stackoverflow.com posts and http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
protected override void OnAuthorization(AuthorizationContext filterContext)
{
// if the controller class or the action has RequireHttps attribute
var requireHttps = (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0
|| filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0);
if (Request.IsSecureConnection)
{
// If request has a secure connection but we don't need SSL, and we are not on a child action
if (!requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "http",
Port = int.Parse(getConfig("HttpPort", "80")) // grab from config; default to port 80
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
else
{
// If request does not have a secure connection but we need SSL, and we are not on a child action
if (requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "https",
Port = int.Parse(getConfig("HttpsPort", "443")) // grab from config; default to port 443
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
base.OnAuthorization(filterContext);
}
#endregion
// a useful helper function to get appSettings value; allow caller to specify a default value if one cannot be found
internal static string getConfig(string name, string defaultValue = null)
{
var val = System.Configuration.ConfigurationManager.AppSettings[name];
return (val == null ? defaultValue : val);
}
Thanks.
Perfect !!! , You have made my day !!!! Thank you!!!
ReplyDelete