Files
SIG-CM2.0/src/api/SIGCM2.Api/Authorization/ForbiddenProblemDetailsHandler.cs

59 lines
2.2 KiB
C#

using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
namespace SIGCM2.Api.Authorization;
/// <summary>
/// Custom IAuthorizationMiddlewareResultHandler that emits a structured ProblemDetails
/// response for 403 Forbidden outcomes (authenticated user, missing permission).
///
/// For 401 Unauthorized and successful outcomes, delegates to the default handler
/// so the existing JWT Bearer challenge flow is unaffected (REQ-B-07).
///
/// Registered as singleton in Program.cs — depends only on framework services.
/// </summary>
public sealed class ForbiddenProblemDetailsHandler : IAuthorizationMiddlewareResultHandler
{
private static readonly AuthorizationMiddlewareResultHandler DefaultHandler = new();
private static readonly JsonSerializerOptions SerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
public async Task HandleAsync(
RequestDelegate next,
HttpContext context,
AuthorizationPolicy policy,
PolicyAuthorizationResult authorizeResult)
{
// Only intercept 403s for authenticated users.
// If the user is not authenticated, the 401 challenge is handled by JwtBearer (REQ-B-07).
if (authorizeResult.Forbidden && context.User.Identity?.IsAuthenticated == true)
{
var requiredPermission = context.Items["RequiredPermission"] as string;
context.Response.StatusCode = StatusCodes.Status403Forbidden;
context.Response.ContentType = "application/problem+json; charset=utf-8";
var problem = new
{
type = "https://sigcm2.local/errors/forbidden",
title = "Acceso denegado",
status = 403,
detail = "No tenés el permiso requerido para ejecutar esta acción.",
permisoRequerido = requiredPermission,
};
await context.Response.WriteAsync(
JsonSerializer.Serialize(problem, SerializerOptions));
return;
}
// Delegate 401 challenges and successful outcomes to the default handler
await DefaultHandler.HandleAsync(next, context, policy, authorizeResult);
}
}