From 9c782fdca4028957df522566e022d16b9910b1f7 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Sat, 8 Jul 2023 07:28:22 -0400 Subject: [PATCH] Initial development (#1) Initial development of this middleware --- .gitignore | 1 - ...tBadger.AspNetCore.CanonicalDomains.csproj | 33 +++++++++ .../CanonicalDomainMiddleware.cs | 43 +++++++++++ .../IApplicationBuilderExtensions.cs | 68 ++++++++++++++++++ .../README.md | 36 ++++++++++ .../icon.png | Bin 0 -> 25176 bytes 6 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 src/BitBadger.AspNetCore.CanonicalDomains/BitBadger.AspNetCore.CanonicalDomains.csproj create mode 100644 src/BitBadger.AspNetCore.CanonicalDomains/CanonicalDomainMiddleware.cs create mode 100644 src/BitBadger.AspNetCore.CanonicalDomains/IApplicationBuilderExtensions.cs create mode 100644 src/BitBadger.AspNetCore.CanonicalDomains/README.md create mode 100644 src/BitBadger.AspNetCore.CanonicalDomains/icon.png diff --git a/.gitignore b/.gitignore index 8a30d25..1b75002 100644 --- a/.gitignore +++ b/.gitignore @@ -378,7 +378,6 @@ FodyWeavers.xsd # VS Code files for those working on multiple tools .vscode/* -!.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json diff --git a/src/BitBadger.AspNetCore.CanonicalDomains/BitBadger.AspNetCore.CanonicalDomains.csproj b/src/BitBadger.AspNetCore.CanonicalDomains/BitBadger.AspNetCore.CanonicalDomains.csproj new file mode 100644 index 0000000..70c76c3 --- /dev/null +++ b/src/BitBadger.AspNetCore.CanonicalDomains/BitBadger.AspNetCore.CanonicalDomains.csproj @@ -0,0 +1,33 @@ + + + + net6.0;net7.0 + enable + enable + 1.0.0 + Initial release + danieljsummers + Bit Badger Solutions + ASP.NET Core middleware to enforce canonical domains + icon.png + README.md + https://bitbadger.solutions/open-source/canonical-domain-middleware/ + false + https://github.com/bit-badger/BitBadger.AspNetCore.CanonicalDomains + Git + MIT License + MIT + aspnetcore middleware canonical + + + + + + + + + + + + + diff --git a/src/BitBadger.AspNetCore.CanonicalDomains/CanonicalDomainMiddleware.cs b/src/BitBadger.AspNetCore.CanonicalDomains/CanonicalDomainMiddleware.cs new file mode 100644 index 0000000..853e8aa --- /dev/null +++ b/src/BitBadger.AspNetCore.CanonicalDomains/CanonicalDomainMiddleware.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; + +namespace BitBadger.AspNetCore.CanonicalDomains; + +/// +/// Middleware to enforce canonical domains +/// +public class CanonicalDomainMiddleware +{ + /// + /// The domains which should be redirected + /// + internal static readonly IDictionary CanonicalDomains = new Dictionary(); + + /// + /// The next middleware in the pipeline to be executed + /// + private readonly RequestDelegate _next; + + /// + /// Constructor + /// + /// The next middleware in the pipeline to be exectued + public CanonicalDomainMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext ctx) + { + if (CanonicalDomains.ContainsKey(ctx.Request.Host.Host)) + { + UriBuilder uri = new(ctx.Request.GetDisplayUrl()); + uri.Host = CanonicalDomains[ctx.Request.Host.Host]; + ctx.Response.Redirect(uri.Uri.ToString(), permanent: true); + } + else + { + await _next.Invoke(ctx); + } + } +} diff --git a/src/BitBadger.AspNetCore.CanonicalDomains/IApplicationBuilderExtensions.cs b/src/BitBadger.AspNetCore.CanonicalDomains/IApplicationBuilderExtensions.cs new file mode 100644 index 0000000..cf43cc0 --- /dev/null +++ b/src/BitBadger.AspNetCore.CanonicalDomains/IApplicationBuilderExtensions.cs @@ -0,0 +1,68 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace BitBadger.AspNetCore.CanonicalDomains; + +/// +/// Extensions on the interface +/// +public static class IApplicationBuilderExtensions +{ + /// + /// Initialize and use the canonical domain middleware + /// + public static IApplicationBuilder UseCanonicalDomains(this IApplicationBuilder app) + { + ParseConfiguration(GetService(app)!.GetSection("CanonicalDomains")); + + if (CanonicalDomainMiddleware.CanonicalDomains.Count > 0) + { + return app.UseMiddleware(); + } + + WarnForMissingConfig(app); + return app; + } + + /// + /// Shorthand for retrieving typed services from the application's service provider + /// + /// The application builder + /// The requested service, or null if it was not able to be found + private static T? GetService(IApplicationBuilder app) => + (T?)app.ApplicationServices.GetService(typeof(T)); + + /// + /// Extract the from/to domain paris from the configuration + /// + /// The CanonicalDomains configuration section + private static void ParseConfiguration(IConfigurationSection? section) + { + if (section is not null) + { + foreach (var item in section.GetChildren()) + { + var nonCanonical = item["From"]; + var canonical = item["To"]; + if (nonCanonical is not null && canonical is not null) + { + CanonicalDomainMiddleware.CanonicalDomains.Add(nonCanonical, canonical); + } + } + } + } + + /// + /// Generate a warning if no configured domains were found + /// + /// The application builder + private static void WarnForMissingConfig(IApplicationBuilder app) + { + var logger = GetService>(app); + if (logger is not null) + { + logger.LogWarning("No canonical domain configuration was found; no domains will be redirected"); + } + } +} diff --git a/src/BitBadger.AspNetCore.CanonicalDomains/README.md b/src/BitBadger.AspNetCore.CanonicalDomains/README.md new file mode 100644 index 0000000..483e85c --- /dev/null +++ b/src/BitBadger.AspNetCore.CanonicalDomains/README.md @@ -0,0 +1,36 @@ +## BitBadger.AspNetCore.CanonicalDomains + +This package provides ASP.NET Core middleware to enforce [canonical domains](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Choosing_between_www_and_non-www_URLs). + +### What It Does + +Having multiple domain names pointing to the same content can lead to inconsistency and diluted search rankings. This middleware intercepts known alternate domains and redirects requests to the canonical domain, ensuring uniformity and unified search rankings. + +_If the ASP.NET Core application is running behind a reverse proxy (Nginx, Apache, IIS, etc.), enforcing these domains at that point is the most efficient. This middleware is designed for scenarios where the application is being served directly or in a container, with multiple domains pointed at the running application._ + +### How to Use + +First, install this package. + +Second, add the configuration for each domain that needs to be redirected; this middleware will configure itself via the details in the `CanonicalDomains` configuration key. An example: + +```json +{ + "CanonicalDomains": [ + { + "From": "www.example.com", + "To": "example.com" + }, + { + "From": "web.example.com", + "To": "example.com" + } + ] +} +``` + +Finally, in your main source file (`Program.cs`, `App.fs`, etc.), import the namespace `BitBadger.AspNetCore.CanonicalDomains`, and call `.UseCanonicalDomains()` on the `IApplicationBuilder` instance. It should be placed after `.UseForwardedHeaders()`, if that is used, but should be ahead of `.UseStaticFiles()`, auth config, endpoints, etc. It should be run as close to the start of the pipeline as possible, as no other processing should take place until the request is made on the canonical domain. + +### Troubleshooting + +This middleware will not throw errors if it cannot parse its configuration properly _(feel free to do the final step before adding configuration to verify!)_. However, if `.UseCanonicalDomains()` is called, and the setup does not find anything to do, it will emit a warning in the log, and will not add the middleware to the pipeline. If redirection is not occurring as you suspect it should, check the top of the log when the application starts. diff --git a/src/BitBadger.AspNetCore.CanonicalDomains/icon.png b/src/BitBadger.AspNetCore.CanonicalDomains/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..da6be2aecde37d3d614f3314a70bcbf0b1b2182f GIT binary patch literal 25176 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 Vtc#mjbM^oL002ovPDHLkV1f;8thWFF literal 0 HcmV?d00001