Bien que Swagger soit un outil indispensable pour documenter et tester les API durant la phase de développement, il est souvent risqué de laisser ces informations accessibles à tous en environnement de production. Une solution efficace consiste à intercepter les requêtes vers l'interface Swagger et à exiger une authentification, par exemple via le protocoel Basic Auth.
Architecture de la solution
Le processus repose sur l'insertino d'un middleware personnalisé dans le pipeline de requêtes ASP.NET Core. Ce composant vérifie si l'URL demandée appartient au chemin Swagger et valide les informations d'identification transmises dans les en-têtes HTTP avant d'autoriser l'accès au fichier index.html ou au JSON de définition.
- Configuration initiale de Swagger
Assurez-vous d'avoir installé le package NuGet Swashbuckle.AspNetCore. Dans votre classe de configuration, commencez par enregistrer le générateur Swagger :
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// Configuration de la génération du document Swagger
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Mon API Sécurisée", Version = "v1" });
});
}
- Création du Middleware d'authentification
Ce middleware intercepte les requêtes dont le chemin commence par "/swagger". Si l'en-tête "Authorization" est absent ou invalide, il renvoie un code d'état 401 (Unauthorized) avec une demande d'authentification Basic.
using Microsoft.AspNetCore.Http;
using System;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
public class FiltreAccesSwagger
{
private readonly RequestDelegate _suivant;
public FiltreAccesSwagger(RequestDelegate suivant)
{
_suivant = suivant;
}
public async Task InvokeAsync(HttpContext contexte)
{
if (contexte.Request.Path.StartsWithSegments("/swagger"))
{
string enTeteAuth = contexte.Request.Headers["Authorization"];
if (enTeteAuth != null && enTeteAuth.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
{
try
{
var valeurEnTete = AuthenticationHeaderValue.Parse(enTeteAuth);
var octets = Convert.FromBase64String(valeurEnTete.Parameter);
var identifiants = Encoding.UTF8.GetString(octets).Split(':', 2);
var utilisateur = identifiants[0];
var motDePasse = identifiants[1];
// Vérification simplifiée des identifiants (à remplacer par une logique sécurisée)
if (utilisateur == "admin" && motDePasse == "P@ssword123")
{
await _suivant(contexte);
return;
}
}
catch
{
// En cas d'erreur de parsing, on continue vers le refus
}
}
// Déclencher la boîte de dialogue de connexion du navigateur
contexte.Response.Headers["WWW-Authenticate"] = "Basic realm=\"Acces Swagger\"";
contexte.Response.StatusCode = 401;
}
else
{
await _suivant(contexte);
}
}
}
- Extension pour faciliter l'enregistrement
Pour une intégration plus propre dans le fichier Startup.cs ou Program.cs, nous créons une méthode d'extension :
using Microsoft.AspNetCore.Builder;
public static class SwaggerSecurityExtensions
{
public static IApplicationBuilder UseSwaggerBasicAuth(this IApplicationBuilder app)
{
return app.UseMiddleware<FiltreAccesSwagger>();
}
}
- Activation dans le pipeline
Il est crucial d'appeler le middleware de sécurité avant d'activer le middleware Swagger. Voici comment configurer la méthode Configure :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Activation de notre protection personnalisée
app.UseSwaggerBasicAuth();
// Activation de Swagger
app.UseSwagger();
app.UseSwaggerUI(config =>
{
config.SwaggerEndpoint("/swagger/v1/swagger.json", "Documentation API v1");
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Désormais, toute tentative d'accès à l'URL /swagger/index.html déclenchera une fenêtre contextuelle du navigateur demandant un nom d'utilisateur et un mot de passe. Cette approche permet de partager la documentation avec des partenaires spécifiques sans exposer publiquement la structure de votre API.