Swagger - Implementando a segurança com autenticação básica


Hoje veremos como implementar a segurança na interface do Swagger que pode ser usada no ambiente de produção..

No .NET 6 quando criamos um projeto Web API, por padrão podemos usar ou não controladores e também podemos integrar a Open API, ou seja, a interface do Swagger em nosso projeto.


Assim criando um projeto API chamado ApiSwagger usando o template ASP .NET Core Web API teremos a integração do serviço do Swagger definida na classe Program conforme o código a seguir:

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
//Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.MapControllers();
app.Run();

Observe que o código habilita o uso do Swagger no ambiente de desenvolvimento. Executando o projeto teremos o resultado a seguir:

Vamos supor que queremos usar o Swagger no ambiente de produção mas desejamos restringir o acesso aos endpoints a apenas usuários autenticados.

Como podemos fazer isso ?

Uma forma bem simples de fazer isso é usar a autenticação básica.

E vamos usar esta abordagem e realizar as seguintes tarefas:

  1. Criar um middleware para realizar a autenticação básica;
  2. Definir um método de extensão para usar o Middleware de autenticação criado;

Para organizar o projeto vamos criar uma pasta SwaggerUtils no projeto e nesta pasta vamos começar criando o middleware de autenticação :

1- SwaggerAuthenticationMiddleware

using System.Net;
using System.Net.Http.Headers;
using System.Text;
namespace ApiSwagger.SwaggerUtils;

public class SwaggerAuthenticationMiddleware
{
    private readonly RequestDelegate next;

    public SwaggerAuthenticationMiddleware(RequestDelegate next)
    {
        this.next = next;
    }
    public async Task InvokeAsync(HttpContext context)
    {
        if (context.Request.Path.StartsWithSegments("/swagger"))
        {
            string authHeader = context.Request.Headers["Authorization"];

            if (authHeader != null && authHeader.StartsWith("Basic "))
            {
                // Pega as credenciais a partir do header do request
                var header = AuthenticationHeaderValue.Parse(authHeader);
                var inBytes = Convert.FromBase64String(header.Parameter);

                var credentials = Encoding.UTF8.GetString(inBytes).Split(':');

                var username = credentials[0];
                var password = credentials[1];

                //valida as credenciais
                if (username.Equals("macoratti") && password.Equals("numsey#123"))
                {
                    await next.Invoke(context).ConfigureAwait(false);
                    return;
                }
            }

            context.Response.Headers["WWW-Authenticate"] = "Basic";
            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        }
        else
        {
            await next.Invoke(context).ConfigureAwait(false);
        }
    }
}

Para simplificar estamos definindo um usuário e senha fixos no código pois não vamos usar um banco de dados.

Agora vamos criar o método de extensão para podermos usar este middleware em nosso projeto. Para isso vamos criar a classe estática SwaggerAuthorization e o método de extensão UseSwaggerAuthorized :

2- UseSwaggerAuthorized

namespace ApiSwagger.SwaggerUtils;

public static class SwaggerAuthorization
{
   public static IApplicationBuilder UseSwaggerAuthorized(this IApplicationBuilder builder)
   {
      return builder.UseMiddleware<SwaggerAuthenticationMiddleware>();
    }
}

Vamos alterar o código do arquivo Program usando o Swagger em produção e o middleware para realizar a autenticação que acabamos de criar:

using ApiSwagger.SwaggerUtils;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

//Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
//{
//    app.UseSwagger();
//    app.UseSwaggerUI();
//}

app.UseAuthorization();
app.UseSwaggerAuthorized();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "SecureSwagger v1"));

app.MapControllers();
app.Run();

Comentei as linhas de código originais e inclui o código para usar o middleware e o swagger sem a restrição de estar no ambiente de desenvolvimento.

Executando o projeto teremos o seguinte resultado:

Em outro artigo podemos abordar como usar um banco de dados para incrementar a segurança.

Pegue o projeto aqui:  ApiSwagger.zip (sem as referências)

"Guia-me na tua verdade, e ensina-me, pois tu és o Deus da minha salvação; por ti estou esperando todo o dia."
Salmos 25:5

Referências:


José Carlos Macoratti