{
"errors": {
"": [
"A non-empty request body is required."
],
"loginRequest": [
"The loginRequest field is required."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-24b434905f3a6770c0e5ac41d0ac025c-d252d9f9f59a0d6f-00"
}
The code functions correctly when I retrieve the JWT key and issuer from the appsettings.json file. However, I encounter an error when attempting to retrieve the username from the request body and fetch the corresponding details from the database. Despite successfully obtaining all the necessary values such as the username, key, issuer, and expiry time from the respective sources, the aforementioned error ('A non-empty request body is required') persists during the execution of the code.why this error occurs even though all the required data seems to be available?
Below is my program.cs.
using NLog;
using NLog.Web;
using System.Text;
using MonetaPRCApi.Utilities;
using Microsoft.OpenApi.Models;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using MonetaPRCApi.Models;
using Newtonsoft.Json;
//For nLog
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
string logFileDirectory = builder.Configuration.GetSection("Logging:LogPath").Get<string>();
LogManager.Configuration.Variables["dirPath"] = logFileDirectory;
// Database connection string
// Register ConfigReader with database connection string
builder.Services.AddScoped<ConfigReader>(provider => new ConfigReader());
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ClockSkew = TimeSpan.Zero // Adjust as needed
};
// Configure JWT issuer and key retrieval from database
options.Events = new JwtBearerEvents
{
OnMessageReceived = async context =>
{
var configReader = context.HttpContext.RequestServices.GetRequiredService<ConfigReader>();
var request = context.HttpContext.Request;
if (request.Path.StartsWithSegments("/api/Login") &&
request.Method.ToLower() == "post") // Adjust the endpoint and HTTP method as needed
{
// Extract username from the request body
var requestBody = await new StreamReader(request.Body).ReadToEndAsync();
var loginRequest = JsonConvert.DeserializeObject<LoginRequest>(requestBody);
var username = loginRequest?.Username;
if (!string.IsNullOrEmpty(username))
{
// Get JWT key and issuer tuple from ConfigReader
var (jwtKey, jwtIssuer, expiryTime) = configReader.GetJwtConfig(username);
if (!string.IsNullOrEmpty(jwtKey) && !string.IsNullOrEmpty(jwtIssuer))
{
// Store JWT key and issuer in request properties for later use
context.HttpContext.Items["JwtKey"] = jwtKey;
context.HttpContext.Items["JwtIssuer"] = jwtIssuer;
// Set JWT parameters for token validation
options.TokenValidationParameters.ValidIssuer = jwtIssuer;
options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey));
}
}
}
}
};
});
builder.Services.AddScoped<Decryption>();
builder.Services.AddScoped<ValidateRequest>();
builder.Services.AddScoped<StoredProcedureExecutor>();
//For Controllers
builder.Services.AddControllers().AddNewtonsoftJson();
//For Authorization in Swagger
builder.Services.AddSwaggerGen(
c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Your API", Version = "v1" });
// Configure JWT authentication in Swagger
var securityScheme = new OpenApiSecurityScheme
{
Name = "Authorization",
Description = "Enter JWT Bearer token",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT"
};
c.AddSecurityDefinition("Bearer", securityScheme);
var securityRequirement = new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
};
c.AddSecurityRequirement(securityRequirement);
}
);
//Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
We need to use EnableBuffering
to allow requests to be reused.
OnMessageReceived = async context =>
{
var configReader = context.HttpContext.RequestServices.GetRequiredService<ConfigReader>();
var request = context.HttpContext.Request;
if (request.Path.StartsWithSegments("/api/Login") && request.Method.ToLower() == "post")
{
// EnableBuffering
request.EnableBuffering();
var requestBody = await new StreamReader(request.Body).ReadToEndAsync();
// reset position of the stream
request.Body.Position = 0;
var loginRequest = JsonConvert...
...
}
}