ASP.NET Core 2.1 no HTTP/HTTPS redirection in App Engine
Somehow I got this to work after creating my own middleware that look for "X-Forwarded-Proto" header according to this hint on Microsoft and App Engine documentation.
Microsoft: Forwarded Headers Middleware must be enabled for an app to process forwarded headers with UseForwardedHeaders.
App Engine: SSL connections are terminated at the load balancer. Traffic from the load balancer is sent to the instance over an encrypted channel, and then forwarded to the application server over HTTP. The X-Forwarded-Proto header lets you understand if the origin request was HTTP or HTTPs.
Microsoft requires the Middleware to be activated first before the app start to process the forwarded headers
So configure the middleware options in ConfigureServices method
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
and use it in Configure method before anything else
app.UseForwardedHeaders();
Then writing the custom middleware that reads the forwarded headers and redirect to HTTPS including queries.
In Configure method
app.Use(async (context, next) =>
{
if (context.Request.IsHttps || context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps)
{
await next();
}
else
{
string queryString = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : string.Empty;
var https = "https://" + context.Request.Host + context.Request.Path + queryString;
context.Response.Redirect(https);
}
});
In the end the Configure method looks like this
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseForwardedHeaders();
app.Use(async (context, next) =>
{
if (context.Request.IsHttps || context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps)
{
await next();
}
else
{
string queryString = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : string.Empty;
var https = "https://" + context.Request.Host + context.Request.Path + queryString;
context.Response.Redirect(https);
}
});
if (env.IsDevelopment())
{
// code removed for clarity
}
else
{
// code removed for clarity
app.UseHsts();
}
app.UseHttpsRedirection();
// code removed for clarity
app.UseMvc();
}
Now navigating to example.com redirect me directly https://www.example.com
This is what worked for me (the code is located in Startup.cs):
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
services.AddHttpsRedirection(opt => opt.HttpsPort = 443);
// code removed for clarity
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
// code removed for clarity
}
else
{
// code removed for clarity
app.UseHsts();
}
app.UseForwardedHeaders();
app.UseHttpsRedirection();
// code removed for clarity
}