Sube carpetas API, API.Tests, Application y Domain del Backend
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using Application.Interfaces.Backup;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace API.Utils.Middlewares;
|
||||
|
||||
/// <summary>
|
||||
/// Returns 503 for every request outside the allow-listed paths while maintenance mode is active.
|
||||
/// </summary>
|
||||
public class MaintenanceModeMiddleware(RequestDelegate next, IMaintenanceModeState maintenanceModeState)
|
||||
{
|
||||
private static readonly string[] AllowedPaths =
|
||||
[
|
||||
"/health",
|
||||
"/api/maintenance",
|
||||
];
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
if (maintenanceModeState.IsActive && !Array.Exists(AllowedPaths, p => context.Request.Path.StartsWithSegments(p)))
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
|
||||
context.Response.Headers.RetryAfter = "30";
|
||||
await context.Response.WriteAsJsonAsync(new
|
||||
{
|
||||
error = "The application is temporarily in maintenance mode.",
|
||||
reason = maintenanceModeState.Reason,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Application.Utils.Constants.Auth;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace API.Utils.Middlewares;
|
||||
|
||||
/// <summary>
|
||||
/// Rejects every request except the user-update and logout endpoints with 403 once CustomClaimTypes.MustChangePassword is set on the caller's token, until the password is changed.
|
||||
/// </summary>
|
||||
public class MustChangePasswordMiddleware(RequestDelegate next)
|
||||
{
|
||||
private static readonly string[] AllowedPaths =
|
||||
[
|
||||
"/api/users/",
|
||||
"/api/auth/logout",
|
||||
];
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
bool mustChange = context.User.FindFirstValue(CustomClaimTypes.MustChangePassword) == "true";
|
||||
|
||||
if (mustChange && !Array.Exists(AllowedPaths, p => context.Request.Path.StartsWithSegments(p)))
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
await context.Response.WriteAsJsonAsync(new
|
||||
{
|
||||
error = "Password change required.",
|
||||
action = "PUT /api/users/{your-id}/password"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace API.Utils.Middlewares;
|
||||
|
||||
/// <summary>
|
||||
/// Logs one compact, structured line per HTTP request: method, path, status code, elapsed time, and correlation id.
|
||||
/// </summary>
|
||||
public class RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
|
||||
{
|
||||
private const string LogTemplate =
|
||||
"HTTP {Method} {PathAndQuery} responded {StatusCode} in {ElapsedMs} ms [{CorrelationId}]";
|
||||
private const string HttpMethodOptions = "OPTIONS";
|
||||
|
||||
/// <summary>
|
||||
/// Times the request, invokes the pipeline, and logs the outcome at a level matched to the response status code.
|
||||
/// </summary>
|
||||
/// <param name="context">The current HTTP context.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
|
||||
await next(context);
|
||||
|
||||
stopwatch.Stop();
|
||||
|
||||
bool isPreflight = context.Request.Method == HttpMethodOptions;
|
||||
int statusCode = context.Response.StatusCode;
|
||||
LogLevel level = statusCode switch
|
||||
{
|
||||
_ when isPreflight => LogLevel.Debug,
|
||||
>= 500 => LogLevel.Error,
|
||||
>= 400 => LogLevel.Warning,
|
||||
_ => LogLevel.Information,
|
||||
};
|
||||
|
||||
logger.Log(
|
||||
level,
|
||||
LogTemplate,
|
||||
context.Request.Method,
|
||||
context.Request.Path + context.Request.QueryString,
|
||||
statusCode,
|
||||
stopwatch.ElapsedMilliseconds,
|
||||
context.TraceIdentifier);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user