How to specify another port with RequireHttps attribute in MVC3

I am just learning ASP.NET MVC, and recently I discovered that the [RequireHttps] attribute automatically redirects a GET request to use SSL, for example ...

[RequireHttps] //apply to all actions in controller public class SomeController { [RequireHttps] //apply to this action only public ActionResult SomeAction() { ... } } 

When using IIS Express as the development server, this successfully redirects the request from http://localhost:55945/... to https://localhost/...

However, on my development system, my project uses HTTPS on port 44300 (this was automatically configured by Visual Studio 2010), and I have not yet found a way to tell MVC to use this port number for redirection, so that it goes to the required https://localhost:43300/...

I really expected this to be automatic, given that the SSL port number was set automatically by Visual Studio, and as far as I can tell, this should be done by all developers using the [RequireHttps] attribute in MVC3. In my search for a solution, I saw several problematic “solutions”, but nothing that seems completely “right” to fix it.

So, do the “right path”, what can I change (both in the source code and in my project configuration) to tell the [RequireHttps] attribute in MVC3 to use the HTTPS port that my project is configured to use?

Or, conversely, is there another other and better “right way” for setting up SSL support in an MVC3 project that does not have this problem?

+8
c # ssl asp.net-mvc-3
source share
4 answers

RequireHttpsAttribute is quite simple and cannot be parameterized to redirect to a specific port. If you really need it, you can subclass and override the HandleNonHttpsRequest method to compose the redirect URL in different ways.

 protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) { base.HandleNonHttpsRequest(filterContext); // redirect to HTTPS version of page string url = "https://" + filterContext.HttpContext.Request.Url.Host + ":" + MyConfig.SslPort + filterContext.HttpContext.Request.RawUrl; filterContext.Result = new RedirectResult(url); } 

However, if your entire site works with HTTPS, you can simply configure in VS in the properties of the web project (Web → Start Action → Start URL) to open the correct HTTPS URL with your port, and not use the redirection function for local testing.

+12
source

A few things that might be helpful.

There is a version of RequireHttpsAttribute in this thread: Where is the source of RequireHttpsAttribute?

There is also an almost identical class RequireSslAttribute on codeplex, mentioned in the same thread. http://aspnet.codeplex.com/SourceControl/changeset/view/63930#391756

Here is an example of an attribute that can be used to switch either from http to https, or from the back based on the TargetUriScheme property. It also includes properties for specifying port numbers.

I decided to use the #if DEBUG block in my constructor to set my local development ports when I build in the Debug configuration. This works for me, since I always create a release during deployment, in which case the port numbers will default to zero and will be left out of the URL.

Port numbers can also be set by applying the attribute to an action method. I could also connect them to a configuration file or other configuration source to determine port numbers at runtime.

 public class ToggleHttpHttpsAttribute : FilterAttribute, IAuthorizationFilter { //supported uri scheme values public enum UriScheme { Http, Https } public ToggleHttpHttpsAttribute( UriScheme uriScheme = UriScheme.Http) { TargetUriScheme = uriScheme; #if DEBUG //set DEBUG ports HttpPort = 55892; HttpsPort = 44301; #endif } private UriScheme TargetUriScheme { get; set; } public int? HttpPort { get; set; } public int? HttpsPort { get; set; } public void OnAuthorization(AuthorizationContext filterContext) { if(filterContext == null) { throw new ArgumentNullException("filterContext"); } bool isHttps = filterContext.HttpContext.Request.IsSecureConnection; if ((isHttps && TargetUriScheme == UriScheme.Http) || (!isHttps && TargetUriScheme == UriScheme.Https)) { ToggleUriScheme(filterContext); } } private void ToggleUriScheme(AuthorizationContext filterContext) { //only allow toggle if GET request if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("ToggleHttpHttpsAttribute can only be used on GET requests."); } filterContext.Result = GetRedirectResult(filterContext); } private RedirectResult GetRedirectResult(AuthorizationContext filterContext) { string prefix = TargetUriScheme == UriScheme.Http ? "http://" : "https://"; int? port = TargetUriScheme == UriScheme.Http ? HttpPort : HttpsPort; string url = string.Format( "{0}{1}{2}{3}", prefix, filterContext.HttpContext.Request.Url.Host, port == null ? "" : string.Format(":{0}", port), filterContext.HttpContext.Request.RawUrl); return new RedirectResult(url); } } 
+2
source

I have the same problem and RequireHttpsAttribute it using the RequireHttpsAttribute rule and the rewrite URL in Web.config . The rewrite rule corresponds to non-standard port numbers and runs ahead of the attribute. You can use the Web.config transform to remove the rewrite rule during deployment, but if you leave it in it, this should have no effect. In production, you will use a standard port number that will not comply with the rule. Then the attribute will catch it.

Here's the rule:

 <system.webServer> <rewrite> <rules> <!-- Redirect HTTP requests to HTTPS, using the non-standard development ports. On deployment, this rule is removed, and the RequireHttpAttribute filter globally applied in SlicerWeb.FilterConfig takes over. This rewrite rule executes before the attribute would be applied, and so can apply the port numbers --> <rule name="HTTPS redirect" stopProcessing="true"> <match url="(.*)" /> <conditions> <add input="{HTTPS}" pattern="off" ignoreCase="true" /> <add input="{SERVER_PORT}" pattern="60470" /> </conditions> <action type="Redirect" url="https://{SERVER_NAME}:44300/{R:1}" redirectType="Found" /> </rule> </rules> </rewrite> </system.webServer> 

The disadvantage of this approach is that you do not rely on the attribute when running locally. But if you applied it once globally, instead of adding it to each controller, this is normal, in my opinion.

+2
source

I am very puzzled by why I had to spend hours trying to get it right. I rewrote the URL in the same way as Scott Hanselman explains:

http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.asp x

This works fine, and I just take out the rewrite rule on my production web server.

0
source

All Articles