Carl Rippon

Building SPAs

Carl Rippon
BlogBooks / CoursesAbout
This site uses cookies. Click here to find out more

Enforcing HTTPS in ASP.NET Core

January 16, 2017
stenciljs

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.

httpsInProjectSettings

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:

chromePrivateConnection

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.:

httpsError

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?}");
    });
}

Want more content like this?

Subscribe to receive notifications on new blog posts and courses

Required
© Carl Rippon
Privacy Policy