Este artigo é parte da série:

Na maior parte das vezes, a melhor forma de garantir a segurança da nossa API será através da tramitação de um token gerado dinamicamente para identificar o usuário que está a está chamando e os direitos que ele possui. No caso do C#, a Microsoft tem até uma biblioteca inteira destinada a isso, que é o Identity Framework, mas não iremos falar dele neste momento e sim como tratar esses tokens.
O token poderia ser apenas mais um parâmetro da função a ser chamada, por exemplo:
public function int Soma (int ValorA, int ValorB, string Token) {...}
Os motivos pelos quais não se deve fazer desta forma serão descrirtos em outro artigo mas, por hora, vamos nos atentar ao fato de que o token deve ser transmitido dentro do HTTP header na diretiva “Authorization”. No exemplo abaixo, os HTTP headers de uma requisição tipo POST e conteúdo JSON, que é a grande maioria dos casos. Ainda a título de exemplo, vamos usar o token “123456”.
authorization: bearer <seu token>
accept: text/plain
content-type: application/json
Como Ler o HTTP Header no C#
É bem simples: basta colar a linha abaixo:
string token = HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
Exemplo aplicado dentro de uma função cujo token tem que ser “123456”:
/// <summary>
/// Soma dois números
/// </summary>
/// <param name="ValorA">Primeiro valor a ser somado</param>
/// <param name="ValorB">Segundo valor a ser somado</param>
/// <returns>A soma do primeiro valor com o segundo valor</returns>
[HttpPost("Soma")]
public ActionResult<int> Soma(int ValorA, int ValorB)
{
string token = HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
if (token != "123456")
{
return Unauthorized($"Acesso não autorizado. Token: [{token}]");
}
int ret = ValorA + ValorB;
return Ok(ret);
}Dessa forma, conseguimos com muita facilidade validar um token manualmente dentro de cada uma das funções, embora haja muitas formas bem mais sofisticadas de fazer isso.
Como Configurar o Swagger para Enviar o Token
Efetuando o procedimento acima, não mais será possível testar a função “Soma” no Swagger, uma vez que não teremos como enviar o token no HTTP header. Para que isso seja possível, faça a seguinte modificação no método AddSwaggerGen() em Program.cs:
using Microsoft.OpenApi.Models;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "Minha API",
Description = "Descrição da minha API",
});
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "Digite o token.",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});Como Fazer a Autenticação a Nível Global
Até o momento estamos fazendo a autenticação manualmente dentro de cada função, porém podemos configurar a REST API para fazer a autenticação a nível global, desta forma não será necessário realizar este processo dentro de cada função.
A título de exemplo, farei aqui uma autenticação manual bem simples. Tudo o que faremos é verificar se o bearer token é igual a “123456”. Com este exemplo fica fácil de você implementar a sua própria lógica para cada programa.
app.UseRouting();
// Autenticação
app.Use(async (context, next) =>
{
var endpoint = context.GetEndpoint();
if (endpoint != null && endpoint.Metadata.GetMetadata<Microsoft.AspNetCore.Authorization.AuthorizeAttribute>() != null)
{
if (!context.Request.Headers.TryGetValue("Authorization", out var authHeader))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Missing Authorization Header");
return;
}
var token = authHeader.ToString().Split(' ').Last();
if (token != "123456")
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Invalid Token");
return;
}
var claims = new[] { new Claim(ClaimTypes.Name, "AuthenticatedUser") };
var identity = new ClaimsIdentity(claims, "Bearer");
var principal = new ClaimsPrincipal(identity);
context.User = principal;
}
await next();
});
app.UseAuthentication();
app.UseAuthorization();Feito isso, vai bastar adicionar a diretiva [Authorize] às funções que necessitam autenticação, no caso da rotina “Soma” que fizemos acima, ela ficaria assim:
/// <summary>
/// Soma dois números
/// </summary>
/// <param name="ValorA">Primeiro valor a ser somado</param>
/// <param name="ValorB">Segundo valor a ser somado</param>
/// <returns>A soma do primeiro valor com o segundo valor</returns>
[HttpPost("Soma")]
[Authorize]
public ActionResult<int> Soma(int ValorA, int ValorB)
{
string token = HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
if (token != "123456")
{
return Unauthorized($"Acesso não autorizado. Token: [{token}]");
}
int ret = ValorA + ValorB;
return Ok(ret);
}Os métodos que não tiverem a diretiva [Authorize] funcionarão de qualquer forma, sem validação do token de autenticação.
Exemplo Completo
Se você está acompanhando a série de artigos explicando como construir uma REST API do zero, nosso “Program.cs” ficou da seguinte forma:
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Reflection;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using Treino_REST_02.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Swagger
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(opts =>
{
opts.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "Treino REST API",
Description = "Como desenvolver um REST API utilizando C# e .NET Core",
TermsOfService = new Uri("https://www.larsoft.com.br/autenticacao-em-2-fatores-2fa-nos-sistemas-larsoft/"),
Contact = new OpenApiContact
{
Name = "Entre em contato com a Larsoft",
Url = new Uri("https://www.larsoft.com.br/institucional/contato/")
},
License = new OpenApiLicense
{
Name = "Como a Larsoft trata a segurança de dados",
Url = new Uri("https://www.larsoft.com.br/institucional/seguranca/")
}
});
opts.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
Name = "Authorization",
Description = "Digite o token.",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
opts.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
opts.IncludeXmlComments(xmlPath, true);
});
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseRouting();
// Autenticação
app.Use(async (context, next) =>
{
if (!context.Request.Headers.TryGetValue("Authorization", out var authHeader))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Missing Authorization Header");
return;
}
var token = authHeader.ToString().Split(' ').Last();
if (token != "123456")
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Token inválido");
return;
}
var claims = new[] { new Claim(ClaimTypes.Name, "AuthenticatedUser") };
var identity = new ClaimsIdentity(claims, "Bearer");
var principal = new ClaimsPrincipal(identity);
context.User = principal;
await next();
});
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.UseDefaultFiles(new DefaultFilesOptions
{
DefaultFileNames = new List<string> { "index.html" }
});
app.UseStaticFiles();
app.Run();Agora, ao executar o Swagger, haverá um botão “Authorize” para que você possa entrar com o token.

Uma vez que tenha entrado com o token, todas as requisições feitas no Swagger daqui para frente, vão carregar o HTTP header “Authorization: Bearer <Token que você digitou>”.
Próxima etapa:
