Enforcing HTTPS in ASP.NET Core
Enforcing ASP.NET Core web apps to use HTTPS is a little different to how you used to do it in previous versions of ASP.NET …
Setting HTTPS Up in Dev
Setting HTTPS up on our development version is simple. Just open the project properties, go to the Debug section, make sure you are running under IIS Express and tick Enable SSL.
Now, you should be able to run the app using the HTTPS URL.
The first time you navigate to the URL you’ll get a warning because the certificate is self-signed. You can however nagivate past this warning to the app’s home page:
Using middleware to enforce HTTPS
Our web app still doesn’t force users to use the HTTPS URL though. In my example, I can still browse to the web app via http://localhost:36313/.
We can force use of the HTTPS URL in ASP.NET Core’s middleware pipeline using the following code in startup.cs
in the Configure
method. Lines 17-28 is where we redirect if the URL is not HTTPS.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
// force users to use https
app.Use(async (context, next) =>
{
if (context.Request.IsHttps)
{
await next();
}
else
{
var withHttps = "https://" + context.Request.Host + context.Request.Path;
context.Response.Redirect(withHttps);
}
});
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
However, when we run the app we get the following error.:
This is because the HTTP and HTTPS ports are different and we haven’t taken that into consideration in our code.
Now, for development, the SSL port is stored in launchSettings.json (under the Properties folder in Visual Studio) under iisSettings > sslPort.
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:36313/",
"sslPort": 44333
}
We can retreive this setting using the following code:
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile(@"Properties/launchSettings.json", optional: false, reloadOnChange: true);
var launchConfig = builder.Build();
sslPort = launchConfig.GetValue<int>("iisSettings:iisExpress:sslPort");
The redirect URL can then be built up as follows:
string sslPortStr = string.Empty;
if (sslPort != 0 && sslPort != 443)
{
sslPortStr = $":{sslPort}";
}
string httpsUrl = $"https://{context.Request.Host.Host}{sslPortStr}{context.Request.Path}";
context.Response.Redirect(httpsUrl);
So, here’s our final pipeline code:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
int sslPort = 0;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile(@"Properties/launchSettings.json", optional: false, reloadOnChange: true);
var launchConfig = builder.Build();
sslPort = launchConfig.GetValue<int>("iisSettings:iisExpress:sslPort");
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.Use(async (context, next) =>
{
if (context.Request.IsHttps)
{
await next();
}
else
{
string sslPortStr = string.Empty;
if (sslPort != 0 && sslPort != 443)
{
sslPortStr = $":{sslPort}";
}
string httpsUrl = $"https://{context.Request.Host.Host}{sslPortStr}{context.Request.Path}";
context.Response.Redirect(httpsUrl);
}
});
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}