Reputation: 1510
So situation sketch:
I've created a website in asp.net core, i've got it up and running. A couple of days ago my hosting provider added the option to configure SSL so I did that leaving me with the problem that there was no redirection from http to https. I've started looking on the web for solutions and figured out some code that works in 3 of the 4 cases on the hosting and 4 of the 4 cases when tested locally on IIS.
So what works:
The following code was used in the asp.net core site:
public void Configure(...) {
app.UseHttpsWorldWideWebRedirect();
}
public static class HttpsWorldWideWebRedirectMiddlewareExtensions
{
public static IApplicationBuilder UseHttpsWorldWideWebRedirect(this IApplicationBuilder builder)
{
return builder.UseMiddleware<HttpsWorldWideWebRedirectMiddleware>();
}
}
public class HttpsWorldWideWebRedirectMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<HttpsWorldWideWebRedirectMiddleware> _logger;
public HttpsWorldWideWebRedirectMiddleware(RequestDelegate next, ILogger<HttpsWorldWideWebRedirectMiddleware> logger)
{
_next = next;
_logger = logger;
_logger.LogInformation("Https WWW redirect module loaded");
}
public async Task Invoke(HttpContext context)
{
var protoHeader = context.Request.Headers["X-Forwarded-Proto"].ToString();
var ignoreHttps = false;
var ignoreWww = false;
if (context.Request.IsHttps || protoHeader.ToLower().Equals("https"))
{
ignoreHttps = true;
}
if (context.Request.Host.Host.StartsWith("www", StringComparison.OrdinalIgnoreCase) || string.Equals(context.Request.Host.Host, "localhost", StringComparison.OrdinalIgnoreCase))
{
ignoreWww = true;
}
if (ignoreWww && ignoreHttps)
{
await _next.Invoke(context);
}
else
{
var www = ignoreWww ? "" : "www.";
var newPath =
$"https://{www}{context.Request.Host.Value}{context.Request.PathBase}{context.Request.Path}{context.Request.QueryString}";
_logger.LogDebug($"'{context.Request.GetDisplayUrl()}' was rewritten into '{newPath}'");
context.Response.Headers["X-Forwarded-Proto"] = "https";
context.Response.Redirect(newPath, true);
}
}
}
The next step I tried was adding a redirect in the web.config to cover that one case where asp.net redirection not works using the following code:
<rewrite>
<rules>
<rule name="Redirect to https if http://www" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^www.*"/>
<add input="{HTTPS}" pattern="Off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
As a test I added "iwork" tot this line:
The result still is err too many redirection but then with http://someurl.com/iworkiworkiworkiworkiworkiworkiworkiworkiworkiwork as resulting url.
So I'm at a loss for what exactly is going wrong and out of ideas on how to fix it, any ideas?
Upvotes: 3
Views: 772
Reputation: 16950
Don't know anything about .NET Core but this can certainly be done with URL rewrite rules.
You need at least 2 rewrite rules.
This will reduce the redirect chain as much as possible.
<rewrite>
<rules>
<rule name="Redirect all http requests to https with www" stopProcessing="true">
<match url=".*" />
<conditions trackAllCaptures="true">
<add input="{HTTP_HOST}" pattern="^localhost" negate="true" />
<add input="{HTTPS}" pattern="off" />
<add input="{HTTP_HOST}" pattern="^(?:www\.)?(.+)$" />
</conditions>
<action type="Redirect" url="https://www.{C:1}/{R:0}" />
</rule>
<rule name="Redirect https requests with no www prefix to https with www" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^localhost" negate="true" />
<add input="{HTTPS}" pattern="on" />
<add input="{HTTP_HOST}" pattern="^www\." negate="true" />
</conditions>
<action type="Redirect" url="https://www.{HTTP_HOST}/{R:0}" />
</rule>
</rules>
</rewrite>
Upvotes: 4
Reputation: 7802
We just faced something very similar in our Azure configuration, and in the end the best way was to use the rewrite module in web.config and not try to handle this in the code.
This is very close to what we added to our server, it should work for you with some minor edits:
<system.webServer>
<rewrite>
<rules>
<rule name="Add WWW">
<match url="^(.*)$" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(?!www\.)(.*)$" />
</conditions>
<action type="Redirect" url="www.{C:0}{PATH_INFO}" redirectType="Permanent" />
</rule>
<rule name="Redirect to HTTPS">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
<add input="{URL}" pattern="/$" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Redirect" url="https://{SERVER_NAME}/{R:1}" redirectType="SeeOther" />
</rule>
</rules>
</rewrite>
</system.webServer>
Here are two sites that have helpful information:
https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-the-url-rewrite-module
http://blog.smarx.com/posts/redirecting-to-https-in-windows-azure-two-methods
Upvotes: 1
Reputation: 557
There is existing Middleware that will handle redirecting to HTTPS for you automatically. Just add the following at the top of your Configure() method in your Startup class:
var options = new RewriteOptions().AddRedirectToHttps();
app.UseRewriter(options);
If you're using APIs, you could also add a RequireHttpsAttribute filter to your MVC Options in ConfigureServices():
services.AddMvc(mvcOptions =>
{
mvcOptions.Filters.Add(new RequireHttpsAttribute());
});
Upvotes: 2