Apresentarei aqui uma forma simples de implementar autenticação por ApiKeys no ASP.NET Core.
Caso sua API tenha uma documentação OpenApi e uma interface Swagger para que outros(ou você mesmo) possam testar mais facilmente, é importante informar nela que sua API fornecece esse tipo de autenticação.
Para isso, no Program.cs
(ou Startup.cs
para templates anteriores ao do .NET6), adicione a configuração:
services.AddSwaggerGen(setup =>
{
string schemeName = "apiKey";
setup.AddSecurityDefinition(schemeName, new OpenApiSecurityScheme
{
Type = SecuritySchemeType.ApiKey,
In = ParameterLocation.Header,
Name = "X-ApiKey",
});
setup.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference= new OpenApiReference
{
Type= ReferenceType.SecurityScheme,
Id= schemeName
}
},
Array.Empty<string>()
}
});
// ... outras configs
}
Tendo isso, você pode verificar que no Swagger UI aparecerá no começo um botão .
Clicando nele, aparecerá a opção para autorizar com o cabeçalho X-ApiKey, conforme definido no código acima.
Até então apenas modificamos a documentação OpenApi, isso na prática não adiciona autorização alguma na aplicação.
É necessário criar um Handler de autenticação para autorizar os acessos por ApiKey,
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using System.Text.Encodings.Web;
namespace MinhaAplicacao;
public class ApiKeyAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public ApiKeyAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) : base(options, logger, encoder, clock) { }
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
await Task.CompletedTask;
string apiKey = Request.Headers["X-ApiKey"];
// Valide a apiKey conforme fizer sentido na sua aplicação
bool isValidApiKey = ...;
if (!isValidApiKey) {
// Creio não ser possível alterar o Body, então adiciono uma mensagem no cabeçalho para o cliente
Response.Headers["x-message"] = "Informe ApiKey valida"; //
return AuthenticateResult.Fail("É necessário informar uma ApiKey válida");
}
var claims = new List<Claim>();
// Adicione claims se fizer sentido para sua aplicação, pode ser que você tenha uma ApiKey para cada cliente.
//claims.Add(new Claim("clienteId", ...);
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new System.Security.Principal.GenericPrincipal(identity, null);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
Então, registre este Handler de autenticação no Program.cs
(ou Startup.cs
):
services.AddAuthentication(config => {
config.AddScheme<ApiKeyAuthenticationHandler>("ApiKey", "API Key");
// Se ApiKey for o único tipo de autenticão na sua aplicação,
// acho conveniente utilizar a linha abaixo.
// Assim é possível usar os atributos [Authorize] sem precisar passar o argumento AuthenticationSchemes.
config.DefaultScheme = "ApiKey";
});
É necessário garantir que os Middleware de autenticação e autorização do ASP.NET Core sejam utilizados, a ordem aqui é importante:
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
Por fim, utilize o atributo [Authorize]
nos Controllers ou Actions que deseja proteger. Nos Endpoints correspondentes deve aparecer a figura de um cadeado: