Skip to content

Commit 951532c

Browse files
committed
feat: Implementa autenticação baseada em API-KEY
1 parent 3da6147 commit 951532c

File tree

4 files changed

+121
-25
lines changed

4 files changed

+121
-25
lines changed

Controllers/HealthCheckController.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text.Json.Nodes;
5-
using System.ComponentModel;
1+
using Microsoft.AspNetCore.Authorization;
62
using Microsoft.AspNetCore.Mvc;
7-
using System.Text.Json.Serialization;
3+
using System.Text.Json.Nodes;
84
using WebApi.Helpers;
95

106

@@ -14,6 +10,7 @@ namespace webapi.Controllers
1410
[Route("/")]
1511
public class HealthCheckController : ControllerBase
1612
{
13+
[AllowAnonymous]
1714
[HttpGet("health-check")]
1815
public IActionResult Check()
1916
{
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Microsoft.AspNetCore.Authorization;
2+
using Swashbuckle.AspNetCore.SwaggerGen;
3+
using Microsoft.OpenApi.Models;
4+
5+
namespace WebApi.Helpers
6+
{
7+
public class SwaggerAllowAnonymousOperationFilter : IOperationFilter
8+
{
9+
public void Apply(OpenApiOperation operation, OperationFilterContext context)
10+
{
11+
var noAuthRequired = context.ApiDescription.CustomAttributes().Any(attr => attr.GetType() == typeof(AllowAnonymousAttribute));
12+
13+
if (noAuthRequired) return;
14+
15+
operation.Security = new List<OpenApiSecurityRequirement>
16+
{
17+
new OpenApiSecurityRequirement
18+
{
19+
{
20+
new OpenApiSecurityScheme
21+
{
22+
Reference = new OpenApiReference
23+
{
24+
Type = ReferenceType.SecurityScheme,
25+
Id = Constant.API_KEY
26+
},
27+
In = ParameterLocation.Header
28+
},
29+
new List<string>()
30+
}
31+
}
32+
};
33+
}
34+
}
35+
}

Middlewares/ApiKeyMiddleware.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using Microsoft.AspNetCore.Authorization;
2+
using WebApi.Models.API;
3+
using WebApi.Models.DTO;
4+
using WebApi.Helpers;
5+
using WebApi.Services;
6+
7+
namespace WebApi.Middlewares
8+
{
9+
10+
public static class ApiKeyValidationMiddlewareExtensions
11+
{
12+
public static IApplicationBuilder UseApiKeyValidationMiddleware(this IApplicationBuilder builder)
13+
{
14+
return builder.UseMiddleware<ApiKeyValidationMiddleware>();
15+
}
16+
}
17+
18+
public class ApiKeyValidationMiddleware
19+
{
20+
private readonly RequestDelegate _next;
21+
22+
public ApiKeyValidationMiddleware(RequestDelegate next)
23+
{
24+
_next = next;
25+
}
26+
27+
public async Task InvokeAsync(HttpContext context, LogService logService)
28+
{
29+
30+
var respFail = new DefRespFail(Constant.MsgStatus401)
31+
{
32+
CodeEvent = logService.LogDTO.CodeEvent,
33+
};
34+
35+
var returnDTO = new ReturnDTO
36+
{
37+
NmMethod = "ValidateApiKey",
38+
StatusCode = StatusCodeApi.UNNAUTHORIZED,
39+
Returnbject = respFail
40+
};
41+
42+
43+
if (context.GetEndpoint()?.Metadata.GetMetadata<IAllowAnonymous>() == null)
44+
{
45+
46+
if (!context.Request.Headers.TryGetValue(Constant.API_KEY, out var extractedApiKey))
47+
{
48+
returnDTO.Info.Add("Api Key was not provided");
49+
context.Response.StatusCode = 401;
50+
logService.LogDTO.Methods.Add(returnDTO);
51+
context.Response.ContentType = "application/json";
52+
await context.Response.WriteAsJsonAsync(respFail);
53+
return;
54+
}
55+
56+
var apiKeyFromEnv = Environment.GetEnvironmentVariable("API_KEY");
57+
apiKeyFromEnv = string.IsNullOrEmpty(apiKeyFromEnv) ? string.Empty : apiKeyFromEnv;
58+
string[] listApiKeyValid = apiKeyFromEnv.Split(';');
59+
60+
if (!Array.Exists(listApiKeyValid, e => e.Equals(extractedApiKey)))
61+
{
62+
returnDTO.Info.Add("Unauthorized client");
63+
context.Response.StatusCode = 401;
64+
logService.LogDTO.Methods.Add(returnDTO);
65+
context.Response.ContentType = "application/json";
66+
await context.Response.WriteAsJsonAsync(respFail);
67+
return;
68+
}
69+
70+
logService.LogDTO.ApiKey = extractedApiKey;
71+
}
72+
73+
await _next(context);
74+
75+
}
76+
}
77+
}

Program.cs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Microsoft.OpenApi.Models;
55
using Swashbuckle.AspNetCore.SwaggerUI;
66
using WebApi.Helpers;
7+
using WebApi.Middlewares;
78
using WebApi.Services;
89

910
var nuVersion = AppHelper.GetNuVersion();
@@ -32,40 +33,24 @@
3233
builder.Services.AddSwaggerGen(o =>
3334
{
3435

35-
3636
o.EnableAnnotations();
3737
o.SwaggerDoc(nuVersion, new OpenApiInfo { Title = nmApplication, Version = nuVersion });
38-
o.AddSecurityDefinition("API-KEY", new OpenApiSecurityScheme
38+
o.AddSecurityDefinition(Constant.API_KEY, new OpenApiSecurityScheme
3939
{
4040
In = ParameterLocation.Header,
4141
Description = "Chave de acesso individual disponibilizado para acessar a API",
42-
Name = "API-KEY",
42+
Name = Constant.API_KEY,
4343
Type = SecuritySchemeType.ApiKey,
4444
Scheme = "ApiKeyScheme"
4545
});
4646

47-
o.AddSecurityRequirement(new OpenApiSecurityRequirement
48-
{
49-
{
50-
new OpenApiSecurityScheme
51-
{
52-
Reference = new OpenApiReference
53-
{
54-
Type = ReferenceType.SecurityScheme,
55-
Id = "ApiKey"
56-
},
57-
In = ParameterLocation.Header
58-
},
59-
new List<string>()
60-
}
61-
});
47+
o.OperationFilter<SwaggerAllowAnonymousOperationFilter>();
6248

6349
o.CustomSchemaIds(x => x.GetCustomAttributes(false).OfType<DisplayNameAttribute>().FirstOrDefault()?.DisplayName ?? x.Name);
6450

6551
var xmlPath = Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml");
6652
o.IncludeXmlComments(xmlPath);
6753

68-
6954
});
7055

7156
#endregion
@@ -111,4 +96,6 @@
11196

11297
app.MapControllers();
11398

99+
app.UseApiKeyValidationMiddleware();
100+
114101
app.Run();

0 commit comments

Comments
 (0)