Reputation: 1
MyAPI.Core.Microservice.API/Program.cs
:
// ...
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddInfrastructureSwagger();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = configuration["Jwt:Issuer"], // Correspondente ao issuer
ValidAudience = configuration["Jwt:Audience"], // Correspondente à audience
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]!))
};
// Adicionando logs de erro para melhor depuração
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Console.WriteLine($"Authentication failed: {context.Exception.Message}");
Console.WriteLine($"Token recebido: {context.Request.Headers["Authorization"]}");
return Task.CompletedTask;
}
};
});
// ...
MyAPI.Core.Microservice.API/Contollers/TokenController.cs
:
namespace MyAPI.Core.Microservice.API.Controllers;
using MyAPI.Core.Microservice.Domain.Models.Entities;
using Microsoft.Extensions.Configuration;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Mvc;
using System.Text;
using Microsoft.Extensions.Logging;
/// <summary>
/// Controlador responsável pela gestão do token de autenticação.
/// </summary>
[ApiController]
[Route("api/auth-token")]
public class TokenController : ControllerBase
{
private readonly string chaveSecreta;
private readonly string issuer;
private readonly string audience;
private readonly string AdmUsername;
private readonly string AdmPassword;
private readonly ILogger<TokenController> _logger;
/// <summary>
/// Construtor do TokenController.
/// </summary>
/// <param name="configuration">Configurações da aplicação, contendo as informações de JWT e credenciais de administrador.</param>
/// <param name="logger">Logger para registrar eventos e erros.</param>
/// <exception cref="ArgumentNullException">Lançado quando as configurações de JWT ou administrador estão ausentes.</exception>
public TokenController(IConfiguration configuration, ILogger<TokenController> logger)
{
issuer = configuration["Jwt:Issuer"]!;
audience = configuration["Jwt:Audience"]!;
chaveSecreta = configuration["Jwt:Key"]!;
AdmUsername = configuration["Adm:Username"]!;
AdmPassword = configuration["Adm:Password"]!;
_logger = logger;
}
/// <summary>
/// Criar um novo token
/// </summary>
/// <param name="admUser">Objeto contendo as credenciais do administrador</param>
/// <returns>Token JWT gerado</returns>
[HttpPost]
[ProducesResponseType(typeof(string), 201)] // Sucesso na criação do token: 200 Good Request
[ProducesResponseType(typeof(object), 400)] // Erro de validação: 400 Bad Request
[ProducesResponseType(typeof(object), 500)] // Erro do servidor: 500 Internal Server Error
public ActionResult<string> GetToken(AdmUser admUser)
{
if(
admUser.Username == AdmUsername &&
admUser.Password == AdmPassword)
{
var tokenJwt = GerarTokenJwt(admUser.Username);
return Ok(tokenJwt);
}
_logger.LogWarning("Administrative credentials incorrect for user: {Username}", admUser.Username);
return BadRequest("Administrative credentials incorrect.");
}
private string GerarTokenJwt(string username)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(chaveSecreta));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new System.Security.Claims.Claim[]
{
new System.Security.Claims.Claim("username", username),
};
var token = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
expires: DateTime.UtcNow.AddHours(1),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
MyAPI.Core.Microservice.API.Client/DependencyInjection/DependencyInjectionSwagger.cs
:
namespace MyAPI.Core.Microservice.API.Controllers;
using MyAPI.Core.Microservice.Domain.Models.Entities;
using Microsoft.Extensions.Configuration;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Mvc;
using System.Text;
using Microsoft.Extensions.Logging;
/// <summary>
/// Controlador responsável pela gestão do token de autenticação.
/// </summary>
[ApiController]
[Route("api/auth-token")]
public class TokenController : ControllerBase
{
private readonly string chaveSecreta;
private readonly string issuer;
private readonly string audience;
private readonly string AdmUsername;
private readonly string AdmPassword;
private readonly ILogger<TokenController> _logger;
/// <summary>
/// Construtor do TokenController.
/// </summary>
/// <param name="configuration">Configurações da aplicação, contendo as informações de JWT e credenciais de administrador.</param>
/// <param name="logger">Logger para registrar eventos e erros.</param>
/// <exception cref="ArgumentNullException">Lançado quando as configurações de JWT ou administrador estão ausentes.</exception>
public TokenController(IConfiguration configuration, ILogger<TokenController> logger)
{
issuer = configuration["Jwt:Issuer"]!;
audience = configuration["Jwt:Audience"]!;
chaveSecreta = configuration["Jwt:Key"]!;
AdmUsername = configuration["Adm:Username"]!;
AdmPassword = configuration["Adm:Password"]!;
_logger = logger;
}
/// <summary>
/// Criar um novo token
/// </summary>
/// <param name="admUser">Objeto contendo as credenciais do administrador</param>
/// <returns>Token JWT gerado</returns>
[HttpPost]
[ProducesResponseType(typeof(string), 201)] // Sucesso na criação do token: 200 Good Request
[ProducesResponseType(typeof(object), 400)] // Erro de validação: 400 Bad Request
[ProducesResponseType(typeof(object), 500)] // Erro do servidor: 500 Internal Server Error
public ActionResult<string> GetToken(AdmUser admUser)
{
if(
admUser.Username == AdmUsername &&
admUser.Password == AdmPassword)
{
var tokenJwt = GerarTokenJwt(admUser.Username);
return Ok(tokenJwt);
}
_logger.LogWarning("Administrative credentials incorrect for user: {Username}", admUser.Username);
return BadRequest("Administrative credentials incorrect.");
}
private string GerarTokenJwt(string username)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(chaveSecreta));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new System.Security.Claims.Claim[]
{
new System.Security.Claims.Claim("username", username),
};
var token = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
expires: DateTime.UtcNow.AddHours(1),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
Errors:
Authentication failed: IDX14100: JWT is not well formed, there are no dots (.).
The token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.
Token recebido: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluQHdhcnJlbi5kb21haW4uY29tIiwiZXhwIjoxNzQwNjA1MjkzLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAifQ.gZXRCeAbphb-WTqu3g3KQFjVyqJPULH31hRreQxnYpk
I've been trying this for days and haven't gotten any results. The funny thing is that following single shot architectures where the dependency file is in the same directory as program.cs
, it works perfectly. It really is a very complex challenge or something that I simply can't see.
Upvotes: 0
Views: 38
Reputation: 1
Okay, I managed to solve the problem, apparently when using Onion architecture you need to be extremely careful with the installation of dependencies, I don't know exactly which dependency solved my error, apparently it's a set of them that makes things work, I'll leave below what I put in all the .csproj of the applications, remembering that this solution is classified as "bad" because I basically copied and pasted the dependencies of the single shot architecture in ALL the onion solutions.
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="ClosedXML" Version="0.102.3" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.72" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="MySql.Data" Version="9.2.0" />
<PackageReference Include="OpenAI" Version="2.1.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageReference Include="QuestPDF" Version="2025.1.1" />
<PackageReference Include="Remote.Linq.Newtonsoft.Json" Version="7.1.0" />
<PackageReference Include="SSH.NET" Version="2024.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="7.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="7.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.2.0" />
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
Upvotes: 0